C# 与.NET Core 2.x中HostBuilder的简单注入器集成
我们正在开发一个运行.NETCore2.x的windows服务。在Steve Gordon的这篇博文之后,事情似乎运行得很好。。。只要我们使用C# 与.NET Core 2.x中HostBuilder的简单注入器集成,c#,.net-core,simple-injector,microsoft.extensions.hosting,C#,.net Core,Simple Injector,Microsoft.extensions.hosting,我们正在开发一个运行.NETCore2.x的windows服务。在Steve Gordon的这篇博文之后,事情似乎运行得很好。。。只要我们使用IServiceCollection。我更喜欢SimpleInjector,但我不确定如何像在asp.net core中那样使用它。我知道有一种方法可以替换这里描述的内置DI,我知道SI团队不推荐这种方法,所以在这个用例中有更好的方法吗 这是我到目前为止所拥有的,但它让人不舒服 --主程序 internal class Program { priv
IServiceCollection
。我更喜欢SimpleInjector,但我不确定如何像在asp.net core中那样使用它。我知道有一种方法可以替换这里描述的内置DI,我知道SI团队不推荐这种方法,所以在这个用例中有更好的方法吗
这是我到目前为止所拥有的,但它让人不舒服
--主程序
internal class Program
{
private static async Task Main(string[] args)
{
var isService = !(Debugger.IsAttached || args.Contains("--console"));
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Runner>();
//configure SimpleInjector here???
});
if (isService)
{
await builder.RunAsServiceAsync();
}
else
{
await builder.RunConsoleAsync();
}
}
}
内部类程序
{
专用静态异步任务主(字符串[]args)
{
var isService=!(Debugger.IsAttached | | args.Contains(“--console”);
var builder=新主机生成器()
.ConfigureServices((主机上下文,服务)=>
{
services.AddHostedService();
//在这里配置SimpleInjector???
});
如果(iService)
{
等待builder.RunAsServiceAsync();
}
其他的
{
等待builder.RunConsoleAsync();
}
}
}
在这里配置容器或多或少会起作用,但主机创建的第一个类(即本例中的
Runner
)由主机创建,并通过IServiceCollection注入任何依赖项。所以我的问题是如何让它从我的SI容器中注入?这里显而易见的答案是。。。没有任何依赖项注入到运行程序中。相反,Runner是表示应用程序入口点的类,所以我在那里配置容器,并在Runner停止时将其处理掉。runner的完整代码
public class Runner : IHostedService, IDisposable
{
private Container _container;
public Runner()
{
_container = new Container();
_container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
}
public Task StartAsync(CancellationToken cancellationToken)
{
Bootstrapper.Bootstrap(_container);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public void Dispose()
{
_container.Dispose();
_container = null;
}
}
我将钩住HostBuilder的ConfigureContainer方法,并在那里设置SimpleInjector,如下所示:
HostBuilder()
.ConfigureContainer<ServiceCollection>((builder, services) =>
{
var container = new Container();
container.RegisterSingleton<IJobRepository, JobRepository>();
services.AddTransient<IHostedService, TimedService>();
})
.ConfigureServices((hostContext, services) =>
{
// Originally we would have done this
//services.AddHostedService<Service>();
})
.Build();
using (host)
{
await host.StartAsync();
await host.WaitForShutdownAsync();
}
这与simpleinjector文档中关于使用ASP.NET Core设置容器的说明一致:
Simple Injector的实践是使用Simple Injector构建应用程序组件的对象图,并让内置容器构建框架和第三方组件,SimpleInjector的实践是使用SimpleInjector构建应用程序组件的对象图,并让内置容器构建框架和第三方组件
这同样适用于.net core和通用HostBuilder。通用主机从服务集合解析托管服务,因此解决方案是在简单注入器中注册托管服务,然后从简单注入器解析托管服务以在服务集合中注册:
HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddLogging();
services.AddOptions();
})
var container = new Container();
var host = new HostBuilder()
//...
.ConfigureServices((context, services) =>
{
container.Collection.Append(typeof(IHostedService), typeof(Runner));
services.AddSingleton(_ => container.GetAllInstances<IHostedService>());
})
//...
.Build();
container.Verify();
await host.RunAsync();
var container=newcontainer();
var host=new HostBuilder()
//...
.ConfigureServices((上下文、服务)=>
{
container.Collection.Append(typeof(IHostedService),typeof(Runner));
services.AddSingleton(=>container.GetAllInstances());
})
//...
.Build();
container.Verify();
等待host.RunAsync();
我不确定我是否理解了您的问题以及您遇到了什么问题。在将Simple Injector与ASP.NET Core集成时,您永远不会替换内置容器,因此不应该使用作为服务运行的东西。因此,您将遵循一种相同的方法,即通过替换框架的一个主要拦截点(如IControllerActivator
)来插入框架。那么,是什么阻止你采取这种做法呢?@Steven是的,我同意这个问题有点含糊不清,我希望Steven Gordon的博客文章能把它说清楚。我已经编辑了这个问题,并将把现在显而易见的答案发布在minute@Steven此外,此处的主机生成器没有IControllerActiviator,因为我没有使用ASP.NET core.:)但是你做得比我好吗?一个请求进来了,那会发生什么?@Steven啊,“请求”实际上是rebus消息。因此,我的引导程序配置服务总线(rebus),该总线进行轮询,并根据需要使用SI适配器建立消息处理程序依赖关系。这难道不意味着运行程序现在是不可测试的吗?