繁体   English   中英

如何将依赖项注入.Net Core项目中的自定义WebHostService中?

[英]How do I inject dependencies into a custom WebHostService in a .Net Core project?

我试图创建所描述的,这将作为Windows服务运行的服务在这里 我的问题是示例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注册。

我的问题是如何访问HostExtensions类中的框架的容器(IServicesCollection),以便可以将必要的依赖项注入MyService 对于MVC控制器,这些操作仅在幕后进行,但我不知道有任何文档详细说明如何在其他地方需要的地方访问它。

您只需花几周的时间就可以使代码生效。

1.在Startup类中将Container设为public static字段:

public class Startup
{
    public static readonly Container container = new Container();

2.将验证从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();

    ...
}

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方法中注册host

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);

    ...
}

我假设myClientFactoryschedulerProvider依赖项已在容器中注册。

4.用来自容器的简单解析替换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>());
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM