.NET CORE编写控制台程序应有的优雅姿势(转载)
原文地址:https://www.cnblogs.com/zuowj/p/11107243.html
本文所說的編寫控制臺程序應有的“正確”方法,我把正確二字加上引號,因為沒有絕對的正確,因人而異,因系統設計需求而異,我這里所謂的正確方法是指使用面向對象,依賴注入IOC,切面控制AOP等編碼規范來提升程序的性能、整潔度、可讀性、可維護性等,最終達到讓人感覺有點高大上,有點優雅的樣子。
先來說說.NET CORE編寫控制臺程序,目前網絡上大把的講解ASP.NET CORE的編寫規范,反而對于.NET CORE控制臺程序編寫規范介紹比較少,大多停留在Hello Word?程序中,而本文則來講講.NET CORE控制臺的編寫規范(應有的優雅姿勢)^ v ^
?如果說不講什么IOC,DI,AOP等,不講擴展性,規范性,全部面向過程(方法)編程,那估計沒什么好講的,因為無非就是定義一個class,然后在class中定義一堆的method(方法),如果在方法中需要使用到其它第三方組件,則直接單獨引用,引用后進行簡單封裝util工具類的靜態方法,甚至也不用封裝,直接使用原生的方法,總之全部都是方法調方法。而這里所演示的編寫控制臺方法均是盡可能的使用.NET CORE所具有的特性,只有這樣才能體現出.NET CORE框架的優勢,否則普通控制臺程序與.NET CORE控制臺程序有什么區別。
編寫.NET CORE控制臺程序優雅姿勢一:(直接使用.NET CORE的 IOC、Logging、Config組件)
代碼如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | //Program.cs using?Microsoft.Extensions.DependencyInjection; using?System; using?Microsoft.Extensions.Logging; using?Microsoft.Extensions.Configuration.Json; using?Microsoft.Extensions.Configuration; using?System.IO; namespace?NetCoreConsoleApp { ????class?Program ????{ ????????static?void?Main(string[] args) ????????{ ????????????//設置config文件 ????????????var?config =?new?ConfigurationBuilder() ????????????????????????????????.SetBasePath(Directory.GetCurrentDirectory()) ????????????????????????????????.AddJsonFile("appSettings.json", optional:?true, reloadOnChange:?true).Build(); ????????????//設置依賴注入 ????????????var?provider =?new?ServiceCollection() ????????????????????????????????????.AddLogging(configLogging =>?//設置日志組件 ????????????????????????????????????{ ????????????????????????????????????????configLogging.SetMinimumLevel(LogLevel.Information); ????????????????????????????????????????configLogging.AddConsole(); ????????????????????????????????????}) ???????????????????????????????????.AddScoped<IConfiguration>(p => config) ???????????????????????????????????.AddScoped<HostService>() ???????????????????????????????????.BuildServiceProvider(); ????????????var?hostService = provider.GetService<HostService>(); ????????????hostService.RunAsync();//統一入口服務 ????????????Console.WriteLine("提示:程序已正常啟動運行,按任意鍵停止運行并關閉程序..."); ????????????Console.ReadLine(); ????????} ????} } //HostService.cs<br> using?Microsoft.Extensions.Configuration; using?Microsoft.Extensions.Logging; using?System; using?System.Diagnostics; using?System.Threading; using?System.Threading.Tasks; namespace?NetCoreConsoleApp { ????public?class?HostService ????{ ????????private?readonly?IConfiguration config; ????????private?readonly?ILogger<HostService> logger; ????????public?HostService(IConfiguration config, ILogger<HostService> logger) ????????{ ????????????this.config = config; ????????????this.logger = logger; ????????} ????????public?void?RunAsync() ????????{ ????????????Task.Run((Action)Execute); ????????} ????????/// <summary> ????????/// 控制臺核心執行入口方法 ????????/// </summary> ????????private?void?Execute() ????????{ ????????????//TODO 業務邏輯代碼,如下模擬 ????????????Stopwatch stopwatch = Stopwatch.StartNew(); ????????????for?(int?i = 1; i <= 100; i++) ????????????{ ????????????????Console.WriteLine("test WriteLine:"?+ i); ????????????????Thread.Sleep(100); ????????????} ????????????stopwatch.Stop(); ????????????logger.LogInformation("Logging - Execute Elapsed Times:{}ms", stopwatch.ElapsedMilliseconds); ????????} ????} } | 
因為要使用.NET CORE相關核心組件,故需要引用相關的NuGet包(引用包的方式有多種方式),而且默認的.NET CORE控制臺只會生成DLL并不會生成EXE啟動程序,故如果僅在WIN系統下使用,還需要設置生成方式等,詳細配置屬性如下:(項目文件csproj)
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>netcoreapp2.2</TargetFramework><RuntimeIdentifiers>win10-x64</RuntimeIdentifiers><SelfContained>false</SelfContained></PropertyGroup><ItemGroup><PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" /><PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" /><PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" /></ItemGroup></Project>?如上代碼雖簡單但代碼編寫順序很關鍵,這里進行說明一下:
1.因為一般應用程序都會有config文件,故我們需要先通過new ConfigurationBuilder來設置config文件的方式及路徑;
2.因為要使用.NET CORE默認的IOC框架,故new?ServiceCollection,然后將相關的依賴服務組件注冊到IOC容器中;
3.config、logging?均是一個程序最基本的依賴組件,故將其注冊到IOC容器中,注冊logging有專門的擴展方法(AddLogging),而config沒有則直接使用通過的注冊方法(當然也可以基于ServiceCollection寫一個AddConfiguration擴展方法)
4.控制臺需要一個核心的入口方法,用于處理核心業務,不要直接在Program中寫方法,這樣就不能使用IOC,同時也沒有做到職責分明,Program僅是程序啟動入口,業務處理應該有專門的入口,故上述代碼中有HostService類(即:核心宿主服務類,?意為存在于控制臺中的服務處理類,在這個類的構造涵數中列出所需依賴的服務組件,以便實例化時IOC可以自動注入這個參數),并注冊到IOC容器中,當然也可以先定義一個IHostService接口然后實現這個接口。(如果有多個HostService類實例,建議定義一個IHostService接口,接口中只需要入口方法定義即可,如:RunAsync)
5.當各組件初始化設置OK、IOC注冊到位后,就應該通過IOC解析獲得HostService類實例,并執行入口方法:RunAsync,該方法為異步后臺執行,即調用該方法后,會在單獨的后臺線程處理核心業務,然后主線程繼續往下面走,輸出關閉提示信息,最后的Console.ReadLine();很關鍵,這個是等待輸入流并掛起當前主線程,目的大家都知道,不要讓控制臺程序關閉。
?通過上述的講解及源代碼展示,有沒有感覺優雅呢?如果覺得這樣還算優雅,那下面展示的第二種更優雅的姿勢
編寫.NET CORE控制臺程序優雅姿勢二:(使用通用主機也稱泛型主機HostBuilder)
代碼如下:Program.cs
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | using?Microsoft.Extensions.DependencyInjection; using?Microsoft.Extensions.Hosting; using?Microsoft.Extensions.Logging; using?NLog.Extensions.Logging; using?Microsoft.Extensions.Configuration; using?System.IO; using?Polly; using?System; namespace?NetCoreConsoleApp { ????class?Program ????{ ????????static?void?Main(string[] args) ????????{ ????????????var?host =?new?HostBuilder() ????????????????.ConfigureHostConfiguration(configHost => ????????????????{ ????????????????????configHost.SetBasePath(Directory.GetCurrentDirectory()); ????????????????}) ????????????????.ConfigureAppConfiguration(configApp => ????????????????{ ????????????????????configApp.AddJsonFile("appsettings.json", optional:?false, reloadOnChange:?true); ????????????????}) ????????????????.ConfigureServices((context, services) => ????????????????{ ????????????????????//添加數據訪問組件示例:services.AddTransient<IDbAccesser>(provider => ????????????????????//{ ????????????????????//??? string connStr = context.Configuration.GetConnectionString("ConnDbStr"); ????????????????????//??? return new SqlDapperEasyUtil(connStr); ????????????????????//}); ????????????????????//添加HttpClient封裝類示例:services.AddHttpClient<GitHubApiClient>() ????????????????????//.AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(3, t => TimeSpan.FromMilliseconds(800))); ????????????????????services.AddHostedService<DemoHostedService>(); ????????????????}) ????????????????.ConfigureLogging((context, configLogging) => ????????????????{ ????????????????????configLogging.ClearProviders(); ????????????????????configLogging.SetMinimumLevel(LogLevel.Trace); ????????????????????configLogging.AddNLog(context.Configuration); ????????????????}) ????????????????.UseConsoleLifetime() ????????????????.Build(); ????????????host.Run(); ????????} ????} } | 
DemoHostedService類代碼:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | using?Microsoft.Extensions.Configuration; using?Microsoft.Extensions.Hosting; using?Microsoft.Extensions.Logging; using?System; using?System.Diagnostics; using?System.Threading; using?System.Threading.Tasks; namespace?NetCoreConsoleApp { ????public?class?DemoHostedService : IHostedService ????{ ????????private?readonly?IConfiguration config; ????????private?readonly?ILogger logger; ????????public?DemoHostedService(IConfiguration config, ILogger<DemoHostedService> logger) ????????{ ????????????this.config = config; ????????????this.logger = logger; ????????} ????????public?Task StartAsync(CancellationToken cancellationToken) ????????{ ????????????Console.WriteLine(nameof(DemoHostedService) +?"已開始執行..."); ????????????//TODO 業務邏輯代碼,如下模擬 ????????????Stopwatch stopwatch = Stopwatch.StartNew(); ????????????for?(int?i = 1; i <= 100; i++) ????????????{ ????????????????Console.WriteLine("test WriteLine:"?+ i); ????????????????Thread.Sleep(100); ????????????} ????????????stopwatch.Stop(); ????????????logger.LogInformation("Logging - Execute Elapsed Times:{}ms", stopwatch.ElapsedMilliseconds); ????????????return?Task.FromResult(0); ????????} ????????public?Task StopAsync(CancellationToken cancellationToken) ????????{ ????????????Console.WriteLine(nameof(DemoHostedService) +?"已被停止"); ????????????return?Task.FromResult(0); ????????} ????} } | 
因為要使用HostBuilder類及相關的.NET CORE組件(如上代碼主要使用到了:Host、Dapper、Nlog、Polly等),故仍需引用相關的NuGet包,詳細配置屬性如下:(項目文件csproj)
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>netcoreapp2.2</TargetFramework><RuntimeIdentifiers>win10-x64</RuntimeIdentifiers><SelfContained>false</SelfContained></PropertyGroup><ItemGroup><PackageReference Include="Dapper" Version="1.60.6" /><PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.2.0" /><PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" /><PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" /><PackageReference Include="Microsoft.Extensions.Http.Polly" Version="2.2.0" /><PackageReference Include="NLog.Extensions.Logging" Version="1.5.1" /><PackageReference Include="System.Collections.Concurrent" Version="4.3.0" /></ItemGroup><ItemGroup><None Update="appsettings.json"><CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory></None><None Update="nlog.config"><CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory></None></ItemGroup></Project>?如上代碼所示,寫過ASP.NET CORE程序的人可能比較眼熟,這與ASP.NET CORE的寫法很類似,是的,你沒有看錯,HostBuilder是通用主機,是可以廣泛應用于非HTTP的環境下,而ASP.NET CORE中的WebHostBuilder?主要用于HTTP WEB環境,使用方式基本類似,都是先定義HostBuilder,然后利用擴展方法注冊、配置各種組件(中間件),最后調用Host的Run方法,開啟后臺服務執行,不同的是WebHostBuilder多了屬于HTTP專有的一些屬性及方法及其適用的中間件。
由于這種寫法比較通用,適用于已熟悉.NET CORE或ASP.NET CORE的人群,上手也較簡單,故建議采取這種方式來寫.NET CORE控制臺程序。需要注意的是HostBuilder中最重要的是:注冊HostedService?服務,如上代碼中的DemoHostedService即是實現了IHostedService接口的宿主后臺服務類,可以定義多個,然后都注冊到IOC中,最后Host會按注冊先后順序執行多個HostedService服務的StartAsync方法,當停止時同樣會執行多個HostedService服務的StopAsync方法
轉載于:https://www.cnblogs.com/huangzelin/p/11128346.html
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的.NET CORE编写控制台程序应有的优雅姿势(转载)的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Java关于 class类的基础方法
- 下一篇: 搭配购买
