如何配置Startup类构造函数可用的DI服务

Zoo*_*Way 5 c# dependency-injection asp.net-core

当我为ASP.NET Core应用程序创建webhost时,我可以指定Startup类而不是实例.

您自己的Startup类的构造函数可以获取通过DI提供的参数.我知道如何为DI注册服务,ConfigureServices但因为那是该类的成员,这些服务不适用于我的启动类的构造函数.

如何注册可用作Startup类的构造函数参数的服务?

原因是我必须提供一个必须在创建webhost之前/之前创建的对象实例,并且我不想以类似全局的样式传递它.

创建IWebHost的代码:

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

构造函数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();
    ...
}
Run Code Online (Sandbox Code Playgroud)

那么具体如何我注册MyClass在这个例子中(这显然必须在之前完成WebStartup由实例化IWebHost)?

Hen*_*ema 9

虽然Steven的关注是有效的,您应该注意它们,但在技术上可以配置用于解析Startup类的DI容器.

ASP.NET托管使用依赖注入来连接您的Startup类的实例,并且还允许我们使用ConfigureServices扩展方法将我们自己的服务添加到该容器IWebHostBuilder:

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

host.Run();
Run Code Online (Sandbox Code Playgroud)

和:

public Startup(IMyService myService)
{
    myService.Test();
}
Run Code Online (Sandbox Code Playgroud)

实际上,所有这一切UseStartup<WebStartup>都是将其作为IStartup托管DI容器的服务实现添加(参见本文).

请注意,将在应用程序容器中再次解析您的服务实例,因为IServiceProvider将构建新的实例.但是,服务的注册将传递给IServiceCollectionStartup类中的应用程序.


Ste*_*ven 7

这是一个"鸡或鸡蛋"问题:在配置之前,您不能让DI容器解析对象图.

然而,您的问题不应该存在,因为正如您应该严格区分容器的注册阶段和解析阶段(正如ASP.NET核心对您强制执行)一样,您应该以同样的方式将注册阶段与之前的阶段分开在哪里加载配置值.

这意味着的是,你在容器的注册阶段需要类应该不会由容器来解决.因为这可能导致难以追查的常见问题.

相反,你应该手动创建类.例如:

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.
}
Run Code Online (Sandbox Code Playgroud)