我正在尝试创建一个将按照here所述的Windows服务运行的服务。我的问题是示例Web Host Service构造函数只接受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
中详细注明了MyService
。
我的问题是如何在HostExtensions类中访问框架的容器(IServicesCollection),以便我可以将必要的依赖项注入roles:elasticsearch
?对于MVC控制器来说,所有这些都只是在幕后处理,但我不知道任何文档详细说明如何在其他地方需要的地方访问它。
答案 0 :(得分:3)
您只需要对代码进行一些小修改即可实现此功能。
Container
类中创建public static
Startup
字段:public class Startup
{
public static readonly Container container = new Container();
Startup
并进入Main
:这样做可以在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();
...
}
MyService
注册为单身人士在容器中单独注册它作为单例允许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();
...
}
MyService
所需的缺少的依赖项。 MyService
取决于主机,loggerFactory,myClientFactory和schedulerProvider,它们目前尚未注册。
host
可以在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
依赖关系已经在容器中注册。
RunAsMyService
扩展方法由于MyService
已在容器中成功注册及其所有依赖项,因此我们现在应该能够从容器中解析它并将其传递给ServiceBase.Run
方法:
public static void Main(string[] args)
{
...
Startup.Container.Verify();
ServiceBase.Run(Startup.Container.GetInstance<MyService>());
}
应该是全部。
最后一点,根据您正在构建的应用程序类型,您可能根本不需要这样精细的Startup
类。您可以将容器的配置移近Main
方法。你是否应该这样做,取决于你实际需要多少。
以下是没有Startup
类的工作示例:
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>());
}