How to configure DI services available to the Startup class constructor

Related searches

When I create the webhost for an ASP.NET Core application I can specify the Startup class but not an instance.

The constructor of your own Startup class can take parameter which are provided through DI. I know how to register services for DI within ConfigureServices but as that is a member of that class these services are not available for the constructor of my startup class.

How do I register services which will be available as constructor parameter of the Startup class?

The reason is that I have to supply an object instance which must be created outside/before the webhost is created and I do not want to pass it in a global-like style.

Code to create the IWebHost:

this.host = new WebHostBuilder()
    .UseConfiguration(config)
    .UseKestrel()
    .UseIISIntegration()
    .UseContentRoot(Directory.GetCurrentDirectory())
    .UseStartup<WebStartup>()
log.Debug("Run webhost");
this.host.Start();

Constructor of WebStartup:

public WebStartup(IHostingEnvironment env, MyClass myClass)
{
    var config = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddEnvironmentVariables()
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
        .Build();
    ...
}

So specifically, how to I register MyClass in this example (which obviously must be done before WebStartup is instanciated by the IWebHost)?

Although Steven's concerns are valid and you should take note of them, it is technically possible to configure the DI container that is used to resolve your Startup class.

ASP.NET hosting uses dependency injection to wire up an instance of your Startup class and also let us add our own services to that container using the ConfigureServices extension method on IWebHostBuilder:

var host = new WebHostBuilder()
    .UseKestrel()
    .UseContentRoot(Directory.GetCurrentDirectory())
    .UseIISIntegration()
    .ConfigureServices(services => services.AddSingleton<IMyService, MyService>())
    .UseStartup<Startup>()
    .Build();

host.Run();

and:

public Startup(IMyService myService)
{
    myService.Test();
}

In fact, all that UseStartup<WebStartup> does is adding it as a service implementation of IStartup to the hosting DI container (see this).

Please note that instances of your services will be resolved again in the application container as a new instance of the IServiceProvider will be built. The registration of the services will, however, be passed to the application IServiceCollection in your Startup class.

App startup in ASP.NET Core, The Startup class configures services and the app's request pipeline. and consumed across the app via dependency injection (DI) or ApplicationServices. public class Startup { public Startup(IConfiguration configuration) The host provides services that are available to the Startup class constructor. Use DI services to configure options. Services can be accessed from dependency injection while configuring options in two ways: Pass a configuration delegate to Configure on OptionsBuilder<TOptions>. OptionsBuilder<TOptions> provides overloads of Configure that allow use of up to five services to configure options:

This is a 'chicken or the egg' problem: You can't let the DI container resolve an object graph before it is configured.

Your problem however should not exist, because just as you should strictly separate the registration phase of the container from the resolve-phase (as ASP.NET Core enforces upon you), the same way should you separate the registration phase from the phase before that where you load configuration values.

What this means is that classes that you require during the registration phase of the container should not be resolved by the container. because that could lead to common problems that are hard to track down.

Instead you should create the class by hand. For instance:

public class Startup
{
    private static MyDependency dependency;

    public Startup(IHostingEnvironment env)
    {
        dependency = new MyDependency();
        var instance = new MyClass(dependency);

        var builder = new ConfigurationBuilder()
            .SetBasePath(instance.ContentRootPath)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        // Register the dependency if it is required by other components.
        services.AddSingleton<MyDependency>(dependency);

        // Add framework services.
        services.AddMvc();

        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    }

    // etc.
}

Dependency injection in ASP.NET Core, Injection of the service into the constructor of the class where it's used. The framework takes on NET Core and Access configuration in Startup. When a service collection extension method is available to register a service:. The startup class contains two methods: ConfigureServices and Configure. ConfigureServices Method. Declaration of this method is not mandatory in startup class. This method is used to configure services that are used by the application. When the application is requested for the first time, it calls ConfigureServices method.

You have an instance of MyClass called myClass and you need to inject that instance into your Startup class. I had a similar requirement and after some experimentation I came up with the following.

First, we inject the myClass instance before we call UseStartup:

var host = new WebHostBuilder()
    // .... other code
    .ConfigureServices(services => services.AddSingleton(myClass)) // Inject myClass instance
    .UseStartup<WebStartup>()

Now we need to get hold of the object in Startup (WebStartup in your case). I wasn't able to find a way to access it from the constructor, but that shouldn't matter as it can be accessed from within the startup class' ConfigureServices() and, if necessary, saved to a field or property from there if it need to be made available to Startup.Configure() which is called later. Here is what I came up with:

    // This goes into Startup.cs/WebStartup.cs
    public virtual void ConfigureServices(IServiceCollection services)
    {
        var myClass = services.Single(s => s.ServiceType == typeof(MyClass)).ImplementationInstance as MyClass;
        if (myClass == null)
            throw new InvalidOperationException(nameof(MyClass) + " instance is null");

        // Now do all the things
    }

I suspect that there may be something in the Framework to retrieve the injected instance more easily, but if not - or until I find it - I can confirm that the above works perfectly!

Avoiding Startup service injection in ASP.NET Core 3: Upgrading to , NET Core in Action, Second Edition is available now, and supports .NET Core NET Core 3; you can not longer inject arbitrary services into the Startup constructor. The second point, injecting services into the Startup class has been As these services are configured in the DI container before Startup is� That said, assuming you are using a Startup class, the other really cool feature of this lack of strong typing is that the class’s methods support dependency injection. The constructor and Configure methods each can request whatever services they may require, and the host will provide them if they’ve previously been configured.

As these services are configured in the DI container before Startup is instantiated, they can be injected into the Startup constructor: public static class Startup {public class Startup {public Startup (IConfiguration configuration, ConnectionStrings ConnectionStrings) // Inject pre-configured service {Configuration = configuration; ConnectionStrings = ConnectionStrings;} public IConfiguration Configuration {get;} public ConnectionStrings ConnectionStrings {get;} public void

Blazor Tutorial Dependency Injection. Dependency Injection (DI) is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. In other words, it is a technique for accessing services configured in a central location. Blazor has built-in support for dependency injection (DI). Blazor applications can use built-in services by having them injected into components.

The IConfiguration is passed in by dependency injection. In Program.cs you can add other types to the DI container, and then add that type to the constructor parameters of Startup.cs. Here’s how it works. The Microsoft.AspNetCore.Hosting.WebHostBuilder has a ConfigureServices () method –

Comments
  • You are right about ASP.NET having 2 internal containers, but are wrong about having to reconfigure them again. The registered IMyService will be available in the application container as well. Problem however is that by building 2 container instances, ASP.NET introduces the problem of a Torn Lifestyle, because when that IMyService is resolved again later on, a new instance is created (since there will be a singleton per container). Reconfiguring that instance in the container will not solve the issue, because you'll still end up with two instances.
  • @Steven you're right. I mixed the part about registration of services and instances of services being created. Thanks for heads up, I'll update my answer.
  • @ZoolWay: My advise it to not use auto-wiring in the WebHostBuilder (i.e. refrain from using one of the AddXXX<TService, TImplementation>() method calls). The only safe method to use is the AddSingleton<T>(T) overload. In other words, create your class by hand, e.g.: services.AddSingleton<IMyService>(new MyService());. This will prevent any future problems such as Torn lifestyles, captive dependencies and other hard to track problems.
  • @ZoolWay: I disagree. You will often be unable to setup your own container at that stage in the pipeline. Further more, I would even suggest keeping application components separated (i.e. in its own container) from framework components.
  • Thanks @Steven - I see the point in separating app and framework containers. Your links and some related directed my to some good thoughts about DI.
  • I cannot create the MyDependency instance within Startup, it must be created before as it needs information not available inside Startup. Passing it through some kind of global would be possible but as the documentation says the constructor of Startup can make use of DI if felt that it would be a better approach to use it.
  • @ZoolWay: Please update your question with this specific information of your exact use case; without this specific information it is impossible to give concrete feedback on this.