Skip to content

Can I inititialize WebHostBuilder with and existing container? #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
hellfirehd opened this issue Mar 14, 2017 · 15 comments
Open

Can I inititialize WebHostBuilder with and existing container? #23

hellfirehd opened this issue Mar 14, 2017 · 15 comments

Comments

@hellfirehd
Copy link

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?

@khellang
Copy link
Member

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.

@hellfirehd
Copy link
Author

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?

@jeremydmiller
Copy link
Contributor

@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.

@khellang
Copy link
Member

khellang commented Apr 3, 2017

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?

@jeremydmiller
Copy link
Contributor

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.

@khellang
Copy link
Member

khellang commented Apr 3, 2017

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?

@jeremydmiller
Copy link
Contributor

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.

@hellfirehd
Copy link
Author

hellfirehd commented Apr 3, 2017

Semantically different works for me. Would child or nested containers be appropriate?

@jeremydmiller
Copy link
Contributor

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.

@joelweiss
Copy link

So is there currently a way to use an existing container?

@zordark
Copy link

zordark commented Oct 31, 2017

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>'

@RubenDelange
Copy link

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 ?

@dazinator
Copy link

dazinator commented Aug 26, 2018

@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'

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.

@whizkidwwe1217
Copy link

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.

@dazinator
Copy link

dazinator commented Jul 27, 2019

@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

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

No branches or pull requests

8 participants