[英]Windows Service with Topshelf on .Net Core that also has a Kestrel API - Dependency Injection Issues
我們在將一些 Windows 服務從 Framework 遷移到 .Net Core 3.1 時遇到了一些問題。
我們目前最掙扎的問題是因為我們實際上有 2 個級別的依賴注入; 一個在 Topshelf 服務級別,一個在 Topshelf.AfterStartingService/Kestrel API 級別。
這意味着當我們使用在 ServiceA 中注冊的服務訪問 ServiceA 控制器時,會出現一個錯誤,指出它無法解析 IPackageRegistrationService
是否有我們缺少的更好的設計模式? 有沒有辦法將這些依賴項傳遞到 Common.Startup 類中,而無需從 Common 項目返回 ServiceA 的循環依賴項?
錯誤看起來像
System.InvalidOperationException:嘗試激活“ServiceA.Console.Registration.Controllers.PackageRegistrationController”時,無法解析“ServiceA.Console.Registration.Service.IPPackageRegistrationService”類型的服務。 在 Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
ServiceA.Main() 像這樣注冊所有依賴項
private static void Main()
{
DbProviderFactories.RegisterFactory("System.Data.SqlClient", SqlClientFactory.Instance);
var configuration = ConfigurationManager.InitialiseConfigurationBuilder().Build();
var mainRabbitQueue = new MonitoredMessageQueue(new RabbitMessageQueue());
// Dependency Injection
var serviceProvider = new ServiceCollection()
// Services
.AddTransient<IReprocessExecuter, ReprocessExecuter>()
.AddTransient<IFileNameBuilder, FileNameBuilder>()
.AddTransient<IRuleRunner, RuleRunner>()
.AddTransient<ITimeReporter, TimeReporter>()
.AddTransient<IPackageRegistrationService, PackageRegistrationService>()
.AddTransient<NetCore.Console.Common.ServiceHost<BatchProcessorService>, NetCore.Console.Common.ServiceHost<BatchProcessorService>>()
// Console.Common
.AddSingleton<IMessageQueue>(mainRabbitQueue)
.AddSingleton<IMessageQueueStats>(mainRabbitQueue)
.AddSingleton<IServiceLogger>(new ServiceEventLogger(mainRabbitQueue))
.AddTransient<IHeartBeatService, HeartBeatService>()
.AddTransient<IStatusService, StatusService>()
.BuildServiceProvider();
using (var serviceHost = serviceProvider.GetService<NetCore.Console.Common.ServiceHost<BatchProcessorService>>())
{
serviceHost.Run();
}
ServiceCommon.Run()
public void Run()
{
HostFactory.Run(x =>
{
x.Service<TService>(s =>
{
s.AfterStartingService(c =>
{
_healthChecker.Start();
if (!string.IsNullOrEmpty(serviceSettings.ApiUri))
{
Startup.ServiceName = serviceSettings.ServiceName;
Startup.StatusService = _statusService;
_apiService = CreateHostBuilder().Build();
_apiService.Start();
_log.LogInformation($"{serviceSettings.ServiceName} API is running, access health check at {serviceSettings.ApiUri}/healthcheck");
}
});
});
});
}
CreateHostBuilder 的樣子
public static IHostBuilder CreateHostBuilder(string[] args = null)
{
return Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseStartup<Startup>()
.UseUrls(ServiceSettings.Default.ApiUri)
.UseSetting(WebHostDefaults.ApplicationKey, Assembly.GetExecutingAssembly().GetName().Name);
});
}
而 StartUp.ConfigureServices 看起來像這樣
public void ConfigureServices(IServiceCollection services)
{
var assembly = Assembly.Load(ServiceName);
services.AddMvc(options =>
{
options.EnableEndpointRouting = false;
}).AddApplicationPart(assembly)
.AddControllersAsServices();
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = $"{ServiceName}",
Version = "v1",
Description = $"{ServiceName}"
});
});
var mainRabbitQueue = new MonitoredMessageQueue(new RabbitMessageQueue());
services.AddSingleton<IMessageQueue>(mainRabbitQueue)
.AddSingleton<IMessageQueueStats>(mainRabbitQueue)
.AddTransient<IHeartBeatService, HeartBeatService>()
.AddSingleton<IStatusService>(StatusService);
}
由Host.CreateDefaultBuilder
在s.AfterStartingService(
創建的通用主機具有新的服務提供者(新的依賴注入容器)。它沒有來自Main
創建的服務提供者的注冊。
在 .NET Core 中,您不需要 Topshelf 將應用程序作為 Windows 服務運行。 使用Microsoft.Extensions.Hosting.WindowsServices
nuget,您可以創建可作為 Windows 服務運行的通用主機,並將 Kestrel 作為托管服務之一。
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseWindowsService()
您可以在主機構建器的Startup
和ConfigureServices
方法中注冊您的類型/服務/依賴項。
關於來自文檔的UseWindowsService
:
將主機生存期設置為 WindowsServiceLifetime,設置內容根,並啟用將應用程序名稱作為默認源名稱記錄到事件日志中。 這是上下文感知的,只有在檢測到進程作為 Windows 服務運行時才會激活。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.