Asp.netCore2.1新功能GenericHost(通用主機)深度學習
什麼是Generic Host ?
這是在Asp.Net Core 2.1加入了一種新的Host,現在2.1版本的Asp.Net Core中,有了兩種可用的Host。
Web Host –適用於託管Web程式的Host,就是我們所熟悉的在Asp.Net Core應用程式的Mai函式中用CreateWebHostBuilder建立出來的常用的WebHost。
clip_image001
Generic Host (ASP.NET Core 2.1版本才有) – 適用於託管非 Web 應用(例如,執行後臺任務的應用)。 在未來的版本中,通用主機將適用於託管任何型別的應用,包括 Web 應用。 通用主機最終將取代 Web 主機,這大概也是這種型別的主機叫做通用主機的原因,在本部落格中,我們將結合原始碼,討論通用主機的工作原理。
為什麼要用通用主機?
通用主機,讓我可以用編寫Asp.Net Core的思想(例如控制反轉、依賴注入、IOC容器)來簡化控制檯應用程式的建立(個人見解),主機負責程式的啟動和生存週期的管理,這對於不處理HTTP請求的應用程式非常有用(處理HTTP請求的是Web應用程式,用Web Host託管),通用主機的目標是將HTTP管道從Web Host中脫離出來,使得Asp.Net Core的那套東西也適用於其他.Net Core程式。
Demo下載
在開始跟隨我分析通用主機之前,大家可以到Github下載這個官方Demo。
https://github.com/aspnet/Docs/tree/master/aspnetcore/fundamentals/host/generic-host/samples/
如果覺得下載一整個比較慢,可以從我的這個Github倉庫下載,沒有其他多餘內容,國內Github比較慢,如果你從官方那個倉庫下載可能會需要很長時間甚至失敗。
https://github.com/liuzhenyulive/Generic-Host-Demo
Generic Host 和Web Host 對比
首先,大家開啟下載下來的這個官方Demo,進入Main函式。
image
可以看到,這簡直就是一個精簡版的Asp.Net Core應用程式,對這個Main函式中出現的所有方法,大家對Asp.Net Core Web應用程式比較熟悉,所以我與Asp.net core 的Webhost做了一個對比,來幫助大家找找感覺。
通用主機 Web主機
new HostBuilder() WebHost.CreateDefaultBuilder(args)
ConfigureAppConfiguration
(用於配置Configuration) WebHost也有這個方法,只是大家預設可能沒有呼叫。
image
ConfigureServices
(用於配置Service,也就是依賴注入) WebHost其實也有ConfigureServices方法,可以這麼呼叫。
image
但是我們一般很少這麼用,一般都是放在Startup的ConfigureServices方法中進行依賴注入。
ConfigureLogging
(是本應用程式所需要的配置,非必需) WebHost還是有!
image
builder.RunConsoleAsync()
image
RunConsoleAsync中其實是對hostbuilder進行
Builder然後Run CreateWebHostBuilder(args).Build().Run();
也就是Main函式中的Build().Run();
無無無無
Startup中的Configure()方法
Asp.net core在此方法中進行Http請求管道的配置
綜上對比,我做了如下概括!
通用主機(Generic Host)有的 Web Host都有。
Web Host的Http Pipeline即Startup.Configure() 在通用主機中沒有。
這就應證了開頭所說的:通用主機的目標是將HTTP管道從Web Host中脫離出來,使得Asp.Net Core的那套東西也適用於其他.Net Core程式。
如何使用?
Run函式解讀
我覺得要知道怎麼用,那麼我們就首先要知道Host的Run方法內到底是在執行什麼?
所以我們深入原始碼,一路F12!
builder.RunConsoleAsync(); =>hostBuilder.UseConsoleLifetime().Build().RunAsync(cancellationToken);=> await host.StartAsync(token);
總算找到了,最關鍵的在這裡。
public async Task StartAsync(CancellationToken cancellationToken = default (CancellationToken))
{
this._logger.Starting();
TaskCompletionSource<object> completionSource1 = new TaskCompletionSource<object>();
ref CancellationToken local = ref cancellationToken;
TaskCompletionSource<object> completionSource2 = completionSource1;
local.Register((Action<object>) (obj => ((TaskCompletionSource<object>) obj).TrySetCanceled()), (object) completionSource2);
IHostLifetime hostLifetime1 = this._hostLifetime;
TaskCompletionSource<object> completionSource3 = completionSource1;
hostLifetime1.RegisterDelayStartCallback((Action<object>) (obj => ((TaskCompletionSource<object>) obj).TrySetResult((object) null)), (object) completionSource3);
IHostLifetime hostLifetime2 = this._hostLifetime;
ApplicationLifetime applicationLifetime = this._applicationLifetime;
hostLifetime2.RegisterStopCallback((Action<object>) (obj => (obj as IApplicationLifetime)?.StopApplication()), (object) applicationLifetime);
object task = await completionSource1.Task;
this._hostedServices = this.Services.GetService>(); foreach (IHostedService hostedService in this._hostedServices) await hostedService.StartAsync(cancellationToken).ConfigureAwait(false
);
this._applicationLifetime?.NotifyStarted();
this._logger.Started();
}
知道大家都喜歡Yellow色,所以我用Yellow把最關鍵的程式碼標示出來了,那麼這些程式碼有什麼含義呢?
this._hostedServices = this.Services.GetService>();
這一行的意思是,從容器中取出所有實現了IHostedService的服務。
這就意味著,我們實現了IHostedService後,需要把該Service註冊到IOC容器中。
foreach (IHostedService hostedService in this._hostedServices)
await hostedService.StartAsync(cancellationToken).ConfigureAwait(false);
執行每個服務的StartAsync方法。
所以,大家是不是冥冥中猜到了怎麼用的呢?大聲笑
我總結的步驟如下:
自定義一個Service,繼承 IHostedService介面。
實現 IHostedService的StartAsync方法,把需要執行的任務放到這個方法中。
把該服務註冊到IOC容器(ServiceCollection)中。
自定義任務的執行
對於步驟1和2,對應的程式碼如下:
public class PrintTextToConsoleService : IHostedService, IDisposable
{
private readonly ILogger _logger;
private readonly IOptions<AppConfig> _appConfig;
private Timer _timer;
public PrintTextToConsoleService(ILogger<PrintTextToConsoleService> logger, IOptions<AppConfig> appConfig)
{
_logger = logger;
_appConfig = appConfig;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Starting");
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
private void DoWork(object state)
{
_logger.LogInformation($"Background work with text: {_appConfig.Value.TextToPrint}");
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
可以看到,在StartAsync中,定義了一個定時任務,帶定時任務每五秒執行一次DoWork方法。
在DoWork方法中,日誌記錄器記錄了一段內容。
因為在Main方法中,對Log進行了如下的配置。
image
所以,一旦日誌記錄了內容,該內容就會在控制檯中輸出。
對於步驟3,對應的程式碼如下
public static async Task Main(string[] args)
{
var builder = new HostBuilder() //例項化一個通用主機
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddJsonFile("appsettings.json", optional: true);
config.AddEnvironmentVariables();
if (args != null)
{
config.AddCommandLine(args);
}
}) //配置Configuration
.ConfigureServices((hostContext, services) =>
{
services.AddOptions();
services.Configure<AppConfig>(hostContext.Configuration.GetSection("AppConfig"));
services.AddSingleton
();
}) //配置Service (依賴注入)
.ConfigureLogging((hostingContext, logging) => {
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
}); //配置Log (本專案中要利用Log把內容在控制檯輸出)
await builder.RunConsoleAsync(); //在控制檯應用程式中執行通用主機
}
黃色部分,把實現了IHostedService介面的PrintTextToConsoleService註冊到容器中。
F5 執行
image
可以看到,控制檯中,每五秒就有一次內容輸出,說明DoWork方法沒五秒被執行了一次,也說明PrintTextToConsoleService的StartAsync被成功呼叫了。
希望本文對幫助大家理解通用主機能夠有所幫助,如果對.Net Core的原始碼分析、潮流新技術感興趣
歡迎關注我
不定期推出實用幹活,謝謝!
參考文獻
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.1
相關文章
- 機器學習&深度學習之路機器學習深度學習
- 機器學習&深度學習 操作tips機器學習深度學習
- 機器學習是深度學習之母機器學習深度學習
- 機器學習、深度學習資源總結機器學習深度學習
- 機器學習和深度學習資源蒐集機器學習深度學習
- 機器學習和深度學習的區別機器學習深度學習
- 機械學習和深度學習的區別深度學習
- 機器學習和深度學習概念入門機器學習深度學習
- 什麼是 AI、機器學習與深度學習?AI機器學習深度學習
- 什麼是AI、機器學習與深度學習?AI機器學習深度學習
- 【機器學習】深度學習開發環境搭建機器學習深度學習開發環境
- 深度學習、機器學習、python、C++視訊深度學習機器學習PythonC++
- 回顧·機器學習/深度學習工程實戰機器學習深度學習
- 瀏覽器裡玩機器學習、深度學習瀏覽器機器學習深度學習
- 人工智慧-機器學習-深度學習:Pointer Network人工智慧機器學習深度學習
- 機器學習/深度學習書單推薦及學習方法機器學習深度學習
- 【深度學習】機率論知識複習深度學習
- 學習筆記【深度學習2】:AI、機器學習、表示學習、深度學習,第一次大衰退筆記深度學習AI機器學習
- [深度學習]多層感知機(MLP)深度學習
- 深度學習與機器學習之間區別 - javaworld深度學習機器學習Java
- 【乾貨】機器學習和深度學習概念入門機器學習深度學習
- 深度學習,機器學習神器,白嫖免費GPU深度學習機器學習GPU
- 【機器學習基礎】關於深度學習的Tips機器學習深度學習
- 深度學習機器學習基礎-基本原理深度學習機器學習
- 深度學習+深度強化學習+遷移學習【研修】深度學習強化學習遷移學習
- 【機器學習】深度學習與經典機器學習的優劣勢一覽機器學習深度學習
- 深度學習及深度強化學習研修深度學習強化學習
- 深度學習學習框架深度學習框架
- 從機器學習談起,深度好文機器學習
- 淺談深度學習中的機率深度學習
- 機器學習、深度學習、強化學習課程超級大列表!機器學習深度學習強化學習
- ####深度學習深度學習
- 深度學習深度學習
- 深度 學習
- 10道機器學習、深度學習必會面試題機器學習深度學習面試題
- 人工智慧-機器學習-深度學習-電子書大全人工智慧機器學習深度學習
- 人工智慧-機器學習-深度學習:Conditional Generation by RNN & Atten人工智慧機器學習深度學習RNN
- 深度學習及深度強化學習應用深度學習強化學習