我如何将依赖项注入到.Net Core项目中的自定义WebHostService中?
作者:互联网
我正在尝试创建一个将作为Windows服务运行的服务,如here所述.我的问题是示例Web主机服务构造函数仅采用IWebHost参数.我的服务需要一个类似以下的构造函数:
public static class HostExtensions
{
public static void RunAsMyService(this IWebHost host)
{
var webHostService =
new MyService(host, loggerFactory, myClientFactory, schedulerProvider);
ServiceBase.Run(webHostService);
}
}
我的Startup.cs文件看起来与此类似:
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.AddInMemoryCollection();
this.Configuration = builder.Build();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
this.container.RegisterSingleton<IConfiguration>(this.Configuration);
services.AddSingleton<IControllerActivator>(
new SimpleInjectorControllerActivator(container));
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
app.UseSimpleInjectorAspNetRequestScoping(this.container);
this.container.Options.DefaultScopedLifestyle = new AspNetRequestLifestyle();
this.InitializeContainer(app, loggerFactory);
this.container.Verify();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
}
private void InitializeContainer(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
container.Register(() => loggerFactory, Lifestyle.Singleton);
container.Register<IMyClientFactory>(() => new MyClientFactory());
container.Register<ISchedulerProvider>(() => new SchedulerProvider());
}
显然,我正在使用Simple Injector作为DI容器.它已在IServiceCollection中注册,如their documentation所述.
我的问题是如何访问HostExtensions类中的框架容器(IServicesCollection),以便可以将必要的依赖项注入MyService?对于MVC控制器,这些操作仅在幕后进行,但我不知道有任何文档详细说明如何在其他地方需要的地方访问它.
解决方法:
您只需花几周的时间就可以使代码生效.
1.在启动类中将容器设为公共静态字段:
public class Startup
{
public static readonly Container container = new Container();
2.将验证从启动中移出,移到主程序中:
这样做可以在完成Startup类之后但在实际启动应用程序之前将额外的注册添加到容器中:
public static void Main(string[] args)
{
...
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(directoryPath)
.UseStartup<Startup>()
.Build();
// Don't forget to remove the Verify() call from within the Startup.
Startup.Container.Verify();
...
}
3.将您的MyService注册为单例
将其显式注册为容器中的Singleton可以使Simple Injector在其上运行诊断,并防止MyService偶然拥有的意外俘获依赖性.您应该将其注册为单例,因为在申请期间它将一直保持活动状态:
public static void Main(string[] args)
{
...
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(directoryPath)
.UseStartup<Startup>()
.Build();
Startup.Container.RegisterSingleton<MyService>();
Startup.Container.Verify();
...
}
3.注册MyService所需的缺少依赖项.
MyService依赖于主机,loggerFactory,myClientFactory和schedulerProvider,它们当前尚未全部注册.
可以在Main方法中注册主机:
public static void Main(string[] args)
{
...
Startup.Container.RegisterSingleton<MyService>();
Startup.Container.RegisterSingleton<IWebHost>(host);
Startup.Container.Verify();
...
}
虽然loggerFactory可以在Startup类中注册:
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
Container.RegisterSingleton(loggerFactory);
...
}
我假设myClientFactory和schedulerProvider依赖项已在容器中注册.
4.用来自容器的简单解析替换RunAsMyService扩展方法
由于MyService已成功以其所有依赖项在容器中注册,因此我们现在应该能够从容器中解析它并将其传递给ServiceBase.Run方法:
public static void Main(string[] args)
{
...
Startup.Container.Verify();
ServiceBase.Run(Startup.Container.GetInstance<MyService>());
}
那应该是全部.
最后一点,根据您所构建的应用程序的类型,您可能根本不需要这么复杂的Startup类.您可以将容器的配置移近Main方法.是否应该这样做取决于您实际需要多少.
这是没有启动类的工作示例:
public static void Main(string[] args)
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new AspNetRequestLifestyle();
IWebHost host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.ConfigureServices(services =>
{
// Configure framework components
services.AddOptions();
})
.Configure(app =>
{
app.UseSimpleInjectorAspNetRequestScoping(container);
// Apply cross-wirings:
container.RegisterSingleton(
app.ApplicationServices.GetRequiredService<ILoggerFactory>());
})
.UseStartup<Startup>()
.Build();
container.RegisterSingleton<MyService>();
container.RegisterSingleton(host);
container.Verify();
ServiceBase.Run(Startup.Container.GetInstance<MyService>());
}
标签:asp-net-core,dependency-injection,c,simple-injector 来源: https://codeday.me/bug/20191111/2023448.html