本文以自己在工作中學習和使用.net core generic-host 作一個總結。
前言
在建立的ASPNETCORE專案中,我們可以在Main()
中看見,我們透過IWebHostBuild
建立了一個IWebHost
,而微軟提供了WebHost.CreateDefaultBuilder(args)
來幫助我們更輕鬆得建立WebHost
。
常常我們的需求不需要建立Web專案,比如後臺任務,那麼我們如何像使用AspNetCore一樣建立控制檯專案。
如何在控制檯程式中建立主機
- 透過
dotnet new console
建立一個控制檯專案 - 透過Nuget新增以下包
- Microsoft.Extensions.Hosting
首先,我們看下IHostBuilder
介面裡的方法
public interface IHostBuilder
{
IHost Build();
IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate);
IHostBuilder ConfigureContainer<TContainerBuilder>(Action<HostBuilderContext, TContainerBuilder> configureDelegate);
IHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate);
IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate);
IHostBuilder UseServiceProviderFactory<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory);
}
ConfigureAppConfiguration()
可以配置應用的一些配置,如環境變數等等ConfigureContainer()
&UseServiceProviderFactory()
可以配置替換預設的依賴註入的元件,比如替換成Autofac
ConfigureHostConfiguration()
可以配置IConfiguration
ConfigureServices()
可以註入服務
接下去,透過以下程式碼,我們可以構建一個簡單的主機。
static void Main(string[] args)
{
CreateDefaultHost(args).Build().Run();
}
static IHostBuilder CreateDefaultHost(string[] args) => new HostBuilder()
.ConfigureHostConfiguration(builder =>
{
//todo
})
.ConfigureAppConfiguration((ctx, builder) =>
{
builder
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{ctx.HostingEnvironment.EnvironmentName}.json", true, true)
.AddEnvironmentVariables()
;
})
.ConfigureServices((ctx, services) =>
{
services.AddLogging();
services.AddHostedService();
})
.UseConsoleLifetime()
;
public class CustomHostService: IHostedService
{
private ILogger _logger;
private Task _executingTask;
public Task StartAsync(...)
{
_logger.LogInformation($"{nameof(CustomHostService):}start");
_executingTask = ExecuteAsync(...);
if(_executingTask.IsCompleted){
return _executingTask;
}
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
}
public Task ExecuteAsync(...)
{
_logger.LogInformation($"{nameof(CustomHostService):executing}")
return Task.Delay(5000);
}
}
如上,我們自定義的 CustomHostService
需要實現 IHostedService
介面,當然,我們可以直接繼承 BackgoundService
類。
在實現了 IHostedService
介面後,我們透過 services.AddHostedService<>()
進行註入,或者透過 service.AddTransient()
進入註入。
啟動以上專案,我們發現,我們的程式預設的Hosting Environment
一直是Production
,那麼如何修改呢 ??
配置環境變數
在AspNetCore專案中,我們可以透過設定環境變數ASPNETCORE_ENVIRONMENT
的值來指定主機環境變數的。而在Generic Host 中暫時沒有這一項配置。
如果檢視IHostBuilder
的擴充套件,我們會發現以下方法:
new HostBuilder()
.UseContentRoot(...)
.UseEnvironment(...)
...
檢視原始碼後,我們可以透過ConfigureHostConfiguration()
方法將這些配置配置到主機中。
現在我們假設我們以DOTNETCORE_ENVIRONMENT
來指定GenericHost的環境。
new HostBuilder().ConfigureHostConfiguration(builder =>
{
builder.AddInMemoryCollection(new Dictionary<string, string>
{
[HostDefaults.EnvironmentKey] = Environment.GetEnvironmentVariable("DOTNETCORE_ENVIRONMENT"),
})
// Nuget:Microsoft.Extensions.Configuration.CommandLine
//.AddCommandLine(args)
;
})
//...
現在讓我們開啟命令列測試下。設定完成環境變數後我們透過dotnet run
啟動程式。檢視輸出,Host Environment 變成為 Stage
# 設定環境變數
$env:DOTNETCORE_ENVIRONMENT='Stage'
# 檢視環境變數
$env:DOTNETCORE_ENVIRONMENT
當然我們也可以透過 commandline 的引數來設定啟動的環境變數等值。
Install-Package Microsoft.Extensions.Configuration.CommandLine
在ConfigureHostConfiguration()
中使用.AddCommandLine(args)
來指定引數。
現在我們可以透過 dotnet run --environment=Development
來指定dev環境了,此時我們發現我們終於成功載入appsettings.Development.json
中的配置資訊了。
使用Autofac來替代預設的 DI
簡單認識一下Autofac
一個第三方的依賴註入容器,相對Microsft.Extensions.DependencyInjection
使用更加簡單方便。
整合到Host中
透過Nuget安裝以下兩個包
Install-Package Autofac
Install-Package Autofac.Extensions.DependencyInection
我們可以使用UseServiceProviderFactory()
和service.AddAutofac()
將預設的DI 替換成 Autofac
;
使用ConfigureContainer()
可以使用Autofac來註入服務;
//省略了非關鍵程式碼
static IHostBuilder CreateDefaultHost(string[] args) => new HostBuilder()
//...略
.ConfigureServices((ctx, services) =>
{
services.AddLogging(x=>{x.AddConsole();});
services.AddAutofac();
})
.ConfigureContainer(builder =>
{
builder.RegisterType()
.As()
.InstancePerDependency();
})
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
//...略
總結
個人認為出現GenericHost解決的幾個痛點,相對AspNetCore中的管道機制,控制檯程式如果不依靠GenericHost來管理Di,想進行大量Microsoft.Extensions
包的整合會非常困難。透過IHostedService,可以方便的進行服務的託管。
原始碼: https://github.com/missxueo/docs-generic-host