asp.net-core - 如何在没有 IHostedService 的情况下正确使用 .Net Core Generic Host?
问题描述
我们有遗留应用程序,我们计划在未来某个时间过渡到 ASP.NET Core API (v2.2)。为了使它更容易,我们决定开始使用具有所有可用功能的通用主机,用于所有未来的增强(appsettings/logging/DI 等)。这个想法是,一旦我们切换到 API,我们将复制主机配置,并且大部分代码将继续工作。我们将 host.Services.GetService() 暴露给遗留代码库,它将用作简单的 ServiceLocator。
问题是:使用这种方法有什么缺点吗?另外,我们需要在通用主机上使用 Start/Stop/Run 吗?根据我所阅读的内容,这仅在运行我们不打算使用的 IHostedService 时需要。我测试了它是否在不调用 Start/Stop 的情况下工作,一切似乎都很好,但我发现的所有示例都调用了 Start/Stop,即使没有 IHostedService。
private IHost _host;
private PricingHost()
{
_host = new HostBuilder()
.UseEnvironment("BETA")
.ConfigureAppConfiguration((hostContext, configApp) =>
{
configApp.SetBasePath(System.IO.Directory.GetCurrentDirectory());
configApp.AddJsonFile("appsettings.json", optional: true);
configApp.AddJsonFile(
$"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json",
optional: true);
})
.ConfigureLogging((hostContext, configLogging) =>
{
configLogging.AddConfiguration(hostContext.Configuration.GetSection("Logging"));
configLogging.AddDebug();
configLogging.AddConsole();
configLogging.AddCustomLogger();
})
.ConfigureServices((hostContext, configServices) =>
{
var startup = new Startup(hostContext.Configuration);
startup.ConfigureServices(configServices);
})
.Build();
}
public T GetService<T>()
{
return _host.Services.GetService<T>();
}
public T GetRequiredService<T>()
{
return _host.Services.GetRequiredService<T>();
}
更新:让我试着澄清一下。我们有 10 年历史的传统 Windows 服务。我们计划在未来某个时候将其转换为 asp.net .net core api,但目前仍在进行 Windows 服务的工作。为了简化未来的过渡,我们希望将通用主机用于 DI、配置访问、日志记录等。我们只是想将其用作服务定位器(因此不需要 IHostedService),但在未来一段时间内能够只需复制所有配置/设置并将其粘贴到新 API 中
在进行小型 POC 之后,我知道这完全有可能,但我想弄清楚是否有任何我应该注意的陷阱以及如何在没有 IHostedService 的情况下正确使用 GenericHost(我是否需要调用 Run/Start/Stop在某些时候或没有必要)?
更新:添加我在这里所做的点网小提琴示例
解决方案
好的,从我的评论和您的回答中,我将尝试找到答案:)
我认为如果你真的需要使用服务定位器模式而不是依赖注入,你也可以在依赖注入中注册IServiceProvider
它本身
第一步:注册服务提供者(IServiceProvider
)
private static IHostBuilder CreateHostBuilder()
{
// One host for all services
return new HostBuilder()
.UseEnvironment("BETA")
.ConfigureAppConfiguration((hostContext, configApp) =>
{
// your configuration
configApp.AddJsonFile("appsettings.json", optional: true);
})
.ConfigureLogging((hostContext, configLogging) =>
{
configLogging.AddConsole();
})
.ConfigureServices((hostContext, configServices) =>
{
// your services
configServices.AddHostedService<PricingHost>();
// register the service provider as singleton
configServices.AddSingleton<IServiceProvider>(sp => sp);
});
}
第二步:使用IHostedService
就像您说的那样,您不想使用IHostedService
,但据我所知,您想实例化多个IHost
类,这最终非常不方便。所以我认为最好的解决方案是在-methodsIHostedServices
中使用旧项目中的代码来实现它,并让它们使用循环或 a来“永远”运行并使用as 服务定位器。StartAsync(...)
while
Task.Delay(forever)
IServiceProvider
// Each service as IHostedService
public class PricingHost : IHostedService
{
// Usage as: Service Locator
private readonly IServiceProvider _serviceProvider;
public PricingHost(IServiceProvider sp)
{
_serviceProvider = sp;
}
public async Task StartAsync(CancellationToken token)
{
Task.Run(() => RunningTask(token));
await Task.Delay(Timeout.Infinite, token);
}
public Task StopAsync(CancellationToken token)
{
return Task.CompletedTask;
}
private Task RunningTask(CancellationToken token)
{
// do your things ...
var logger = _serviceProvider.GetRequiredService<ILogger<PricingHost>>();
logger.LogInformation("Working...");
return Task.CompletedTask;
}
}
如果您查看我在 dotnet fiddle 上的简短示例,可能会更清楚
如果有任何不清楚的地方,请给我留言。也许我没有弄明白为什么你想在你的应用程序中有多个主机。
推荐阅读
- php - 如何配置 PHP 以自动定期删除会话数据/sess_ 文件?
- python - Flask - ModuleNotFoundError,虽然它在同一个文件夹中 - 更新
- swift - 创建的 observable 不会发出任何东西
- java - 如何在不使用 response.getBody() 或 Content-length 标头参数的情况下知道响应正文的内容长度?
- c - 联合定义中的`sizeof`结构
- websocket - Akka HTTP - Websocket - 真正的双向场景
- powershell - Invoke-AzVMRunCommand 日志输出、错误处理
- selenium - 如何使用基于机器学习的算法/基于人工智能的自动化为任何损坏的图像创建测试套件
- excel - RegExp vs IRegExp2:类名混淆
- go - 带有 Postgres 的 Gorm 有一个作为 JSON 的嵌套结构