-
Notifications
You must be signed in to change notification settings - Fork 312
Allow external service providers (#550 and #1309) #1322
Changes from 6 commits
b1ad979
da37dab
fc23c07
207af1d
8190d24
75a5b5b
a83e93e
4526219
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -153,7 +153,7 @@ public IWebHost Build() | |
|
||
var hostingServices = BuildCommonServices(out var hostingStartupErrors); | ||
var applicationServices = hostingServices.Clone(); | ||
var hostingServiceProvider = hostingServices.BuildServiceProvider(); | ||
var hostingServiceProvider = GetProviderFromFactory(hostingServices); | ||
|
||
if (!_options.SuppressStatusMessages) | ||
{ | ||
|
@@ -202,6 +202,14 @@ public IWebHost Build() | |
host.Dispose(); | ||
throw; | ||
} | ||
|
||
IServiceProvider GetProviderFromFactory(IServiceCollection collection) | ||
{ | ||
var provider = collection.BuildServiceProvider(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm after thinking bit, we might need to dispose the temporary container we created If there's an if (factory != null)
{
using (provider)
{
return factory.CreateServiceProvider(factory.CreateBuilder(collection))
}
}
return provider; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You don't want to do that. In case factory is resolved from a type and had any disposable dependencies this code will discard these but it might still be used in the provider. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any service provider we create should be disposed so that services get disposed. The provider may not be collected if there’s a singleton relying on dispose to unroot itself (we had an example recently where a timer was causing problems). The reasons it’s ok here is because we’re creating a whole new container anyways so disposing services after creation should be fine. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understand |
||
var factory = provider.GetService<IServiceProviderFactory<IServiceCollection>>(); | ||
|
||
return factory?.CreateServiceProvider(factory.CreateBuilder(collection)) ?? provider; | ||
} | ||
} | ||
|
||
private IServiceCollection BuildCommonServices(out AggregateException hostingStartupErrors) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,6 +71,34 @@ public void Configure(IApplicationBuilder app) => | |
$"{ctx.RequestServices.GetRequiredService<SimpleService>().Message}, {ctx.RequestServices.GetRequiredService<TestService>().Message}")); | ||
} | ||
|
||
[Fact] | ||
public async Task ExternalContainerInstanceCanBeUsedForEverything() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does this verify the custom container is being used? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How would you like it to be verified? Can you think of all your comments and do them all at once? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not that familiar with your testing framework, I used one of the tests as example and run it in debugger to verify. Feel free to change it any way you like. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Heh, sorry, I have a bad habit of re-reviewing things where they are big changes. A good test would be to add a service in the ExternalContainer implementation and make sure it's resolved in the Startup constructor. I would also not add a test to TestServerTests.cs I would add a test to https://github.com/aspnet/Hosting/blob/dev/test/Microsoft.AspNetCore.Hosting.Tests/WebHostBuilderTests.cs There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this it? Think about it, I am catching flight in a few hours. I have time just for one more change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can take over if you want. It's pretty much done. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would appreciate if you do. I am getting low on time. |
||
{ | ||
var builder = new WebHostBuilder() | ||
.UseStartup<CustomContainerStartup>() | ||
.ConfigureServices(s => // Register outside provider instance | ||
s.AddSingleton<IServiceProviderFactory<IServiceCollection>>(new ExternalContainerFactory())); | ||
|
||
var host = new TestServer(builder); | ||
|
||
var response = await host.CreateClient().GetStringAsync("/"); | ||
|
||
Assert.Equal("ApplicationServicesEqual:True", response); | ||
} | ||
|
||
public class ExternalContainerFactory : IServiceProviderFactory<IServiceCollection> | ||
{ | ||
public IServiceCollection CreateBuilder(IServiceCollection services) | ||
{ | ||
return services; | ||
} | ||
|
||
public IServiceProvider CreateServiceProvider(IServiceCollection containerBuilder) | ||
{ | ||
return containerBuilder.BuildServiceProvider(); | ||
} | ||
} | ||
|
||
public class ThirdPartyContainer | ||
{ | ||
public IServiceCollection Services { get; set; } | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At present configured factories are ignored and builder uses hardcoded
hostingServices.BuildServiceProvider()
. Instead it should check if proper factory is registered and if yes, use it to create provider.Fall back on hardcoded call if nothing is registered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I almost like this change. Lets instead build the service provider another time:
It's a bit more robust.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done