這是在Asp.Net Core 2.1加入了一種新的Host,如今2.1版本的Asp.Net Core中,有了兩種可用的Host。git
通用主機,讓我能夠用編寫Asp.Net Core的思想(例如控制反轉、依賴注入、IOC容器)來簡化控制檯應用程序的建立(我的看法),主機負責程序的啓動和生存週期的管理,這對於不處理HTTP請求的應用程序很是有用(處理HTTP請求的是Web應用程序,用Web Host託管),通用主機的目標是將HTTP管道從Web Host中脫離出來,使得Asp.Net Core的那套東西也適用於其餘.Net Core程序。github
在開始跟隨我分析通用主機以前,你們能夠到Github下載這個官方Demo。web
https://github.com/aspnet/Docs/tree/master/aspnetcore/fundamentals/host/generic-host/samples/json
若是以爲下載一整個比較慢,能夠從個人這個Github倉庫下載,沒有其餘多餘內容,國內Github比較慢,若是你從官方那個倉庫下載可能會須要很長時間甚至失敗。app
https://github.com/liuzhenyulive/Generic-Host-Demoasync
首先,你們打開下載下來的這個官方Demo,進入Main函數。函數
能夠看到,這簡直就是一個精簡版的Asp.Net Core應用程序,對這個Main函數中出現的全部方法,你們對Asp.Net Core Web應用程序比較熟悉,因此我與Asp.net core 的Webhost作了一個對比,來幫助你們找找感受。源碼分析
綜上對比,我作了以下歸納!ui
這就應證了開頭所說的:通用主機的目標是將HTTP管道從Web Host中脫離出來,使得Asp.Net Core的那套東西也適用於其餘.Net Core程序。this
我以爲要知道怎麼用,那麼咱們就首先要知道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<IEnumerable<IHostedService>> (); 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<IEnumerable<IHostedService>>();
這一行的意思是,從容器中取出全部實現了IHostedService的服務。
這就意味着,咱們實現了IHostedService後,須要把該Service註冊到IOC容器中。
foreach (IHostedService hostedService in this._hostedServices)
await hostedService.StartAsync(cancellationToken).ConfigureAwait(false);
執行每一個服務的StartAsync方法。
因此,你們是否是冥冥中猜到了怎麼用的呢?
我總結的步驟以下:
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進行了以下的配置。
因此,一旦日誌記錄了內容,該內容就會在控制檯中輸出。
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<IHostedService, PrintTextToConsoleService>
(); }) //配置Service (依賴注入) .ConfigureLogging((hostingContext, logging) => { logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); logging.AddConsole(); }); //配置Log (本項目中要利用Log把內容在控制檯輸出) await builder.RunConsoleAsync(); //在控制檯應用程序中運行通用主機 }
黃色部分,把實現了IHostedService接口的PrintTextToConsoleService註冊到容器中。
能夠看到,控制檯中,每五秒就有一次內容輸出,說明DoWork方法沒五秒被執行了一次,也說明PrintTextToConsoleService的StartAsync被成功調用了。
但願本文對幫助你們理解通用主機可以有所幫助,若是對.Net Core的源碼分析、潮流新技術感興趣
歡迎關注我
不按期推出實用幹活,謝謝!
參考文獻
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.1