seesharper/LightInject.Microsoft.DependencyInjection

Implement IServiceProviderFactory for use in generic hosts

Closed this issue Β· 12 comments

It seems that if you want to use LightInject with the new generic host in .NET Core 2.1 (Microsoft.Extensions.Hosting) , you have to provide an implementation of IServiceProviderFactory in LightInject.Microsoft.DependencyInjection.

Have a look here: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.1#container-configuration
(note the text at the start of the page: "The Generic Host is under development to replace the Web Host in a future release and act as the primary host API in both HTTP and non-HTTP scenarios.).

Something like

public static IHostBuilder UseLightInject(this IHostBuilder hostBuilder)
{
    hostBuilder.UseServiceProviderFactory(new LightInjectServiceProviderFactory());
    return hostBuilder;
}

public class LightInjectServiceProviderFactory : IServiceProviderFactory<ServiceContainer>
{
    private IServiceCollection _services;
    private ServiceContainer _serviceContainer;

    public ServiceContainer CreateBuilder(IServiceCollection services)
    {
        _services = services;
        _serviceContainer = new ServiceContainer();
        return _serviceContainer;
    }

    public IServiceProvider CreateServiceProvider(ServiceContainer containerBuilder)
    {
        var provider = containerBuilder.CreateServiceProvider(_services);
        var lifetime = provider.GetService<IApplicationLifetime>();
        lifetime.ApplicationStopped.Register(() => _serviceContainer.Dispose()); //If I don't do this the process will hang when I terminate it (ctrl+c)
        return provider;
    }
}

I think this actually calls for a new package as it is not really part of the dependency injection abstractions.

Maybe something like LightInject.Microsoft.AspNetCore.Hosting

Hi Bernhard
IServiceProviderFactory is part of Microsoft.Extensions.DependencyInjection(.Abstractions) and is used by IHostBuilder which is part of Microsoft.Extensions.Hosting(.Abstractions), so it is not a ASP.NET thing :-)

Hi @seesharper,

I was wondering if there has been any progress made on this issue? I'm in the process of building an app using the .NET Core 2.1 Generic Host with LightInject as the DI container but have encountered the failure to exit problem.

I've tried the code suggested above on 28th May 2018 (registering with IApplicationLifetime.ApplicationStopped) but this doesn't solve the failure to shutdown the app. The registered delegate function is getting called during app shutdown and calls .Dispose() on the service container.

I was wondering if it was something to do with the container root Scope begun by the CreateServiceProvider extension method not being ended, but my knowledge of the internals of how LightInject works is admittedly limited.

Any suggestions would be appreciated.

Typically, after spending over a day looking at this I manage to solve it within minutes of posing the question.

I modified the code from above to this:

public class LightInjectServiceProviderFactory : IServiceProviderFactory<ServiceContainer>
{
    private IServiceCollection _services;
    private ServiceContainer _serviceContainer;

    public ServiceContainer CreateBuilder(IServiceCollection services)
    {
        _services = services;
        _serviceContainer = new ServiceContainer();
        return _serviceContainer;
    }

    public IServiceProvider CreateServiceProvider(ServiceContainer containerBuilder)
    {
        var provider = containerBuilder.CreateServiceProvider(_services);
        var lifetime = provider.GetService<IApplicationLifetime>();
        lifetime.ApplicationStopped.Register(() => 
        {
            _serviceContainer.Dispose();
            _serviceContainer.ScopeManagerProvider.GetScopeManager(_serviceContainer)
                .CurrentScope.Dispose();
        }); //If I don't do this the process will hang when I terminate it (ctrl+c)
        return provider;
    }
}

Please let me know if I'm doing something massively wrong here.

@goldenbeard I don't think you are doing anything massively wrong πŸ˜€The LightInject adapter creates a "root" scope which probably would have to be disposed. As long as it works it should be okay. After all this is just before the app ends πŸ˜€

@blankensteiner

ServiceProviderFactory is part of Microsoft.Extensions.DependencyInjection(.Abstractions) and is used by IHostBuilder which is part of Microsoft.Extensions.Hosting(.Abstractions), so it is not a ASP.NET thing :-)

No but the UseLightInject extension method from LightInject.Microsoft.AspNet.Hosting extends the IWebHostBuilder and not the IHostBuilder which is the generic host. Hence the need for another package. The reason I've put this on hold is that the word on the street is that everything will eventually be based on the generic host. But up until now this is somewhat unclear. https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.2

Seems like it is coming though
aspnet/Hosting#1580 (comment)

@davidfowl This is something coming in 3.0, right?

Yep!

Hi @seesharper,
Correct me if I'm wrong, but it doesn't appear that any of the content discussed in this issue is resolved in the new release of seesharper/LightInject.Microsoft.AspNetCore.Hosting?

Hi again @goldenbeard

The IServiceProviderFactory was introduced here
3f23546#diff-4205119d44407f0a3d99f06bfb799c73

Its implementation is in this repo so that it can be used outside of a web host.

For a .Net3.0 generic host we can do something like

public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices(services =>
                {
                    services.AddHostedService<Worker>();
                })
                .UseServiceProviderFactory(new LightInjectServiceProviderFactory());

We could of course have create a package called LightInject.Microsoft.Hosting and had a UseLightInject extending the IHostBuilder. That would be a very small package though since it will basically just call into UseServiceFactory πŸ˜€

So for generic hosts, we don't need the LightInject.Microsoft.AspNetCore.Hosting package. Only the LightInject.Microsoft.DependencyInjection package.