当我为ASP.NET Core应用程序创建webhost时,我可以指定Startup
类,但不能指定实例。
您自己的Startup类的构造函数可以获取通过DI提供的参数。我知道如何在ConfigureServices
内为DI注册服务,但由于这是该类的成员,这些服务不适用于我的启动类的构造函数。
如何注册可用作Startup类的构造函数参数的服务?
原因是我必须提供一个必须在创建webhost之前/之前创建的对象实例,并且我不想以类似全局的样式传递它。
创建IWebHost的代码:
this.host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseIISIntegration()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<WebStartup>()
log.Debug("Run webhost");
this.host.Start();
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();
...
}
具体来说,如何在此示例中注册MyClass
(显然必须在WebStartup
实现IWebHost
之前完成?)
答案 0 :(得分:9)
虽然史蒂文的担忧是有效的,你应该注意它们,但技术上可以配置用于解析你的启动类的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();
和
public Startup(IMyService myService)
{
myService.Test();
}
事实上,UseStartup<WebStartup>
所做的就是将其作为IStartup
的服务实现添加到托管DI容器(see this)。
请注意,将在应用程序容器中再次解析您的服务实例,因为将构建IServiceProvider
的新实例。但是,服务的注册将传递到Startup类中的应用程序IServiceCollection
。
答案 1 :(得分:7)
这是一个'鸡或蛋'问题:在配置之前,你不能让DI容器解析对象图。
然而,您的问题不应该存在,因为正如您应该严格区分容器的注册阶段和解析阶段(如ASP.NET核心强制执行),您应该将注册阶段与注册阶段分开在您加载配置值之前的阶段。
这意味着在容器的注册阶段您需要的类应该不由容器解析。因为这可能导致common problems难以追踪。
相反,您应该手动创建类。例如:
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.
}
答案 2 :(得分:0)
您有一个名为MyClass
的{{1}}实例,需要将该实例注入到myClass
类中。我有类似的要求,经过一些实验后,我提出了以下建议。
首先,我们在调用Startup
之前注入myClass
实例
UseStartup
现在,我们需要掌握var host = new WebHostBuilder()
// .... other code
.ConfigureServices(services => services.AddSingleton(myClass)) // Inject myClass instance
.UseStartup<WebStartup>()
中的对象(在您的情况下为Startup
)。我无法找到从构造函数访问它的方法,但这无关紧要,因为可以从启动类的WebStartup
中访问它,并在必要时将其保存到字段或属性中。如果需要将其提供给ConfigureServices()
,稍后再调用。这是我想出的:
Startup.Configure()
我怀疑框架中可能有某些内容可以更轻松地检索注入的实例,但是如果不能-或直到我找到它,我可以确认以上内容是否完美!