ipjohnson / Grace.DependencyInjection.Extensions

Grace Extensions for ASP.Net Core
19 stars 7 forks source link

Configuration for AspNetCore 3.0 + Blazor #16

Closed houseofcat closed 2 years ago

houseofcat commented 5 years ago

Hey Ian, its me - the pain again! Testing out the AspNetCore 3.0 support while waiting to use the 7.1.0 release.

public void ConfigureContainer(IInjectionScope scope)
{
    scope.Configure(c =>
    {
        c.ExportInstance(
            new DataSource(MainConnectionString, RedisConnectionString, true))
            .AsKeyed<IDataSource>("main");

        c.ExportInstance(
            new DataSource(LoggingConnectionString, RedisConnectionString, true))
            .AsKeyed<IDataSource>("logging");
    });
}

Got to this point... but I am a little lost. No access to the global container? Or more likely, I missed a step/something. I hit the UnitTests to see an example/for instance in AspNetCore but couldn't find one.

So, basically, how do we...

Container.Locate<IDataSource>(withKey:"main")

...within our code after just configuring scope and using AspNetCore hosting.

I also gambled and figured since we are injecting that factory into AspNetCore hosting @inject might work, but I couldn't figure that out/or simply doesn't work with instances in this case.

In a Blazor page, much like a Razor page, you would normally call this: @inject IDataSource Main

Hence the idea of an immediate workaround is to find my/any global static DI Container, then simply...

public IDataSource MainDs { get; set; } => Container.Locate<IDataSource>(withKey:"main")

...but again I need a specific instance to pull out. Just hoping you could give me some hints on if I can proceed this way and possibly how!

Thanks for all your hard work, I know this is all cutting edge tech stack. I understand if its just out of scope at this time.

Tristan

ipjohnson commented 5 years ago

Hi @houseofcat

ASP.Net Core doesn't really have the idea of a static container. Technically you could save off the IInjectionScope to a static but I would recommend against that.

I haven't played with blazor yet but I would have thought the @inject tag would work the same.

If you can put together a simple example I'll take a look because it should just work.

houseofcat commented 5 years ago

Thanks for the response, when I am working on it I will post a snippit.

houseofcat commented 5 years ago

I am just pinging to let you know I should have a sample app for you to triage shortly, thanks for keeping the issue open.

ipjohnson commented 5 years ago

Hi @houseofcat

Where can I find the sample?

houseofcat commented 5 years ago

Got somethings figured out now...

Ported Business/Structural logic to a web.api and have grace and AspNetCore 3.0 working but without key lookups.

public void ConfigureContainer(IInjectionScope scope)
{
    scope.Configure(c => c.ExportInstance(new DataSource(MainConnectionString, RedisConnectionString, true)).As<IDataSource>());
}
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private IDataSource DataSource { get; set; }

    public WeatherForecastController(IDataSource dataSource)
    {
        DataSource = dataSource;
    }

    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        if (DataSource == null) throw new Exception("Dependency null");

        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = rng.Next(-20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

^ The above is working (as in the DataSource is not null).

The following configuration and usage below does not work currently.

public void ConfigureContainer(IInjectionScope scope)
{
    scope.Configure(c => c.ExportInstance(new DataSource(MainConnectionString, RedisConnectionString, true)).AsKeyed<IDataSource>("main"));
}
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    [Import(Key = "main")]
    private IDataSource DataSource { get; set; }

    public WeatherForecastController()
    { }

    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        if (DataSource == null) throw new Exception("Dependency null");

        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = rng.Next(-20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

So if you could lend a hint to get it working, great, if not I will have to adjust my code which isn't the end of the world.

ipjohnson commented 5 years ago

Sorry I meant to reply to this earlier. Try putting the Import attribute on the parameter for constructor injection. You could do something more complex to setup property injection but probably the simplest solution would be to add the attribute to the constructor parameter.

houseofcat commented 5 years ago

Hey Ian, that's what I tried, the import one is the one failing in AspNetCore 3 - sorry I wasn't clear enough - [Import(Key = "main")].

The simple one (i.e. the first one) is working just fine.

ipjohnson commented 5 years ago

Grace won't automatically inject fields or properties without being configured. Sorry just to be clear you tried the attribute directly on the parameter?

    public WeatherForecastController([Import(Key = "main")]IDataSource dataSource)
    {
        DataSource = dataSource;
    }
houseofcat commented 2 years ago

Holy smokes, sorry for leaving this open @ipjohnson .

I resolved the issue many moons ago, none of this is really needed now.