StructureMap.Microsoft.DependencyInjection
StructureMap.Microsoft.DependencyInjection copied to clipboard
Can I inititialize WebHostBuilder with and existing container?
The call to .UseStructureMap() expects nothing or a Registry. Either way it creates a brand new container.
I would prefer to use an existing container with cross cutting services that the entire application uses, not just WebHost.
This could be done if there was a .UseStructureMap(IContainer) overload. Is there any interest in this? Or is it a bad idea and if so, why?
The whole reason there is a UseStructureMap
method is for the ASP.NET Core host to automatically wire up the container. This means also calling Startup.ConfigureContainer
with the specific TContainerBuilder
, before the container is built. In this case, it would call it with an IContainer
instance, which makes it a bit weird when you want to keep configuring the registry. I'll have to think a bit about this one.
I understand that. In my app ASP.NET is only a small component. It's essentially only providing a Web UI/API to a long running daemon and database. The daemon relies heavily on IoC/DI and needs to share services with the ASP.NET bit.
In theory I could take the Deluge approach with a deluge.web and a deluge.daemon but I'd really rather have it all self contained in a single process that starts and stops together like NZBGet or Sonarr.
See where I'm going with this?
@khellang @dougkwilson We suddenly need this feature at work for hybrid aspnet core/service bus apps. One of us will get a PR in for this one this week.
There's already a PR at #24 (although that seems to have drifted pretty far out of scope by now). The question I have is; how valuable is this? Is this just a way to pass the container into Startup
? The container is already built by the time it's passed into ConfigureContainer
. What are you going to do with it?
One way or another, we just need an easy recipe to build a new ASP.Net Core app by handing it an existing StructureMap Container. The immediate use case for us is an application that uses both a service bus framework and ASP.Net Core, and both need to add their own registrations to the StructureMap Container.
I think this is valuable. I was actually under the impression that we already had this before last week.
Oh, I definitely think passing a pre-configure container is valuable, but I'm just not sure this is the way to go. If we bring this in as-is, it could be very confusing for the user; depending on which overload of UseStructureMap
you call (the one taking a Registry
or IContainer
), the ASP.NET Core hosting layer will look for a different ConfigureContainer
overload. This might not be obvious for the end user. Maybe we can rectify this with documentation?
Instead of an overload of UseStructureMap
, what if it's semantically different like UseExistingStructureMapContainer(IContainer)
? I do agree on the potential user confusion. We had similar issues with that w/ fubumvc.
Semantically different works for me. Would child or nested containers be appropriate?
Child containers, maybe, nested no. If you were sharing the container w/ some other piece of infrastructure but needed to override some things, I guess a Child container would work.
So is there currently a way to use an existing container?
You can pass initialized container to Startup class directly.
public class Startup : IStartup {
private IContainer _container;
public Startup(IConfiguration configuration, IContainer container)
{
Configuration = configuration;
_container = container;
}
public IConfiguration Configuration { get; }
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Register additional stuff
// .....
// populate the container using the service collection.
_container.Populate(services);
return _container.GetInstance<IServiceProvider>();
}
public void Configure(IApplicationBuilder app)
{
//do additional work
}
}
After that you should instantiate Startup and build host
var container = new Container();
// configure container
// .......
var configurationBuilder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
var configuration = configurationBuilder.Build();
var startup = new Startup(configuration, container);
var builder = WebHost.CreateDefaultBuilder()
.UseSetting(WebHostDefaults.ApplicationKey, typeof(Startup).Assembly.GetName().Name)
.ConfigureServices(services => services.AddSingleton<IStartup>(startup))
.UseKestrel(options =>
{
options.Listen(IPAddress.Loopback, 1113);
});
var host = builder.Build();
You can read this article for some details.
But be careful with child container, I don't know why, but some dependencies (e.g. registered as singleton or open generic) cannot be resolved, when using child container.
This code will fail
var container = new Container();
var configurationBuilder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
var configuration = configurationBuilder.Build();
var startup = new Startup(configuration, container.CreateChildContainer());
var builder = WebHost.CreateDefaultBuilder()
.UseSetting(WebHostDefaults.ApplicationKey, typeof(Startup).Assembly.GetName().Name)
.ConfigureServices(services => services.AddSingleton<IStartup>(startup))
.UseKestrel(options =>
{
options.Listen(IPAddress.Loopback, 1113);
});
var host = builder.Build();
Above code will fail, when try to resolve IServer instance within WebHost class, with exception
StructureMap.StructureMapConfigurationException : No default Instance is registered and cannot be automatically determined for type 'IOptions<KestrelServerOptions>'
I'm also interested in a way to use an existing container. Our solution has console apps, Windows services, web apps that all use the same logic to initialize the container. Is there a good example to achieve this with ASP.NET Core 2.1 ?
@zordark
Above code will fail, when try to resolve IServer instance within WebHost class, with exception StructureMap.StructureMapConfigurationException : No default Instance is registered and cannot be automatically determined for type 'IOptions<KestrelServerOptions>'
I am also having a problem with IOptions<T>
. Perhaps this is related to #43
I have submitted a PR with a failing test case to demonstrate the issue, but I haven't been able to fix it.
I'm also having problems with this in ASP.NET Core 3 for months now. I'm using SassKit library and it requires an existing container.
@whizkidwwe1217 perhaps try dotnettency instead of saaskit? I created it to solve issues I was having with saaskit and it works with asp.net core 3.0: https://github.com/dazinator/Dotnettency
I tend to use the autofac package rather than the structuremap though, as seen here: https://github.com/dazinator/Dotnettency/blob/develop/src/Sample.AspNetCore30.RazorPages/Sample.AspNetCore30.RazorPages.csproj so if you do use the structuremap package your mileage may vary