Skip to content
This repository has been archived by the owner on Dec 19, 2018. It is now read-only.

Allow resolving Startup from external service provider #1309

Closed
ENikS opened this issue Jan 10, 2018 · 9 comments
Closed

Allow resolving Startup from external service provider #1309

ENikS opened this issue Jan 10, 2018 · 9 comments

Comments

@ENikS
Copy link
Member

ENikS commented Jan 10, 2018

When Unity container is configured to replace built in DI engine we discovered that it is not being used to create and resolve Startup class.

Currently WebHost builder is hard coded to create new built-in/internal service provider and resolve Startup class from that provider. Configured provider is ignored and created later. As result no types registered with Unity are available to the Startup constructor.

For more information please see this project

@Tratcher
Copy link
Member

Probable duplicate of #1060

@ENikS
Copy link
Member Author

ENikS commented Jan 10, 2018

@Tratcher No, it has nothing to do with collection

@ENikS
Copy link
Member Author

ENikS commented Jan 10, 2018

As you can see on line 156 WebHostBuilder calls ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(serviceCollection) to get service provider. BuildServiceProvider simply creates new provider with no regards to configuration and registered factory:

public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options)
{
    if (services == null)
    {
        throw new ArgumentNullException(nameof(services));
    }

    if (options == null)
    {
        throw new ArgumentNullException(nameof(options));
    }

    return new ServiceProvider(services, options);
}

@pksorensen
Copy link

pksorensen commented Jan 27, 2018

I come to the same conclusion as @ENikS and also tried to relay this to @davidfowl at some point, but i failed to create a repro/ convey the problem.

https://twitter.com/pksorensen/status/851840194311487488

@davidfowl
Copy link
Member

I’m not clear on what’s being asked for here. The WebHostBuilder cannot function with just an already built IServiceProvider, it needs to be an IServiceCollection (which is the issue that @Tratcher linked)

@davidfowl
Copy link
Member

Ah I just read the other repository. You’re specifically talking about the hosting container itself (there’s always 2). Im not sure that’s possible with the way things are designed today. We would need to not DI activate the IServiceProviderFactory which it is today.

I’m not sure this is doable without hacks or breaking changes but we’d be open to looking at pull requests.

@ENikS
Copy link
Member Author

ENikS commented Jan 30, 2018

The solution is rather simple. Requires changing of 3 lines of code. Sent you a PR

@scottt732
Copy link

scottt732 commented Jan 30, 2018

In #1060, @davidfowl you said "This isn't possible today. The WebHostBuilder is the root of the DI universe and you can't replace the built in IServiceCollection." I'm curious whether this is true for HostBuilder as well. I would assume if I'm adding AspNetCore and RabbitMq that there is some concept of isolated scopes between those two things? I gather this is the distinction between 1 hosting service provider and in this case 2 application service providers? Is it possible to have more than 1 AspNetCore runtime in a process w/isolated configuration/dependencies (i.e., UseKestrel(), UseHttpSys(), localhost:5000, localhost:5001)?

To be clear, I want to replace the container that gets a WebHost (Startable, Stoppable, Disposable thing). I don't need to/care to resolve MVC internals or the stuff supplied to ASP.NET Core via user-supplied code. If the WebHostBuilder/HostBuilder layer (which I presume is the 1 hosting service provider above) does allow us to create one with an existing DI container, what's the harm in services at that host layer from being made available to the application service providers (and not the other way around).

I'm not advocating for this lambda-type approach specifically, but something along these lines:
http://autofaccn.readthedocs.io/en/latest/lifetime/working-with-scopes.html#adding-registrations-to-a-lifetime-scope
In my mind, ideally container is for host-level services, the builder inside the lambda for application-specific services (AddMvc(), etc.). This would provide isolation between adjacent RabbitMQ/ASP.NET Core stacks with the exception of shared registrations from the host-level. This is impossible right now as far as I can tell b/c (a) Microsoft's DI library doesn't have this child scopes concept and because (b) the IServiceProviderFactory interface operates on an IServiceCollection and ContainerBuilder that the framework constructs for me. It won't allow me to bring my own.

Is this chicken/egg impossible or just the interfaces/code in place won't allow it? Like is it worth expending the effort to try and build a PR/workaround for or is this truly a dead-end? I have a truly miserable workaround after like dozens of hours of pain involving registering the root container as a backup Autofac registration source and letting the AutofacServiceProvider handle the 404-scenarios with a secondary lookup. It becomes really tricky to manage the lifetime of things and I do end up having to register a built container as a singleton in the ServiceCollection that WebHostBuilder insists on creating.

@ENikS
Copy link
Member Author

ENikS commented Jan 30, 2018

@scottgu #1322 should solve your problem as well.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants