前情提要 筆者收到主管的指示,要來寫一個執行檔(exe
)程式,筆者離這種exe
程式好久遠了,自從轉換到Web
領域後幾乎都是寫API為主,一開始從.net MVC5
開始進入Web
領域,寫了幾年的Razor View
後,前一份工作剛好前後端分離,前幾年都在寫dotnet core web api
及angular
為主,Console Application
離我好遙遠阿,但筆者已經被dotnet core
的內建DI
機制及AppSettings
當Config
已經習以為常,對於Console Application
來說這些都是要自己實作上去的,不妨藉由這次機會來實作看看。
筆者看了幾篇部落格後,想法是仿照dotnet core web api
標準配置那樣
有一個Startup
類別
Startup
類別中有public get
的Configuration
,令其他有需求的人可以存取Configuration
物件
Startup
中宣告ConfigureServices
,並將配置好的ServiceCollection
回傳
宣告一個App
類別,主要有Run
這個Method
,最終於Program
中執行
製作商業邏輯Service 筆者這支的主要用意是檢查某個服務是否正常,可以想見驗證方式分為
ping test
http request test
對於應用程式來說,由注入時決定該用哪個方式即可,直接來看Code
吧
1 2 3 4 public interface IPingTestService { Task<bool > PingHost (string hostName ) ; }
接著實作上面列到的兩種方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class PingTestByPingService : IPingTestService { public async Task<bool > PingHost (string hostName ) { bool pingable = false ; Ping pinger = null ; try { pinger = new Ping(); PingReply reply = await pinger.SendPingAsync(hostName); pingable = reply.Status == IPStatus.Success; } finally { if (pinger != null ) { pinger.Dispose(); } } return pingable; } }
1 2 3 4 5 6 7 8 9 10 11 public class PintTestByHttpRequestService : IPingTestService { public async Task<bool > PingHost (string hostName ) { var result = false ; using var httpClient = new HttpClient(); var response = await httpClient.GetAsync(hostName); result = response.StatusCode == HttpStatusCode.OK; return result; } }
到這邊商業邏輯實作告一段落了,就先放在一邊,回頭把基礎建設都用好
製作Startup類別 我們要製作Startup
類別中的AppSettings
及DI
機制需要爾外安裝相關的微軟提供套件,就先來安裝nuget
套件們吧
1 2 3 4 5 6 dotnet add package Microsoft.Extensions.Configuration dotnet add package Microsoft.Extensions.Configuration.Binder dotnet add package Microsoft.Extensions.Configuration.Json dotnet add package Microsoft.Extensions.DependencyInjection
安裝好nuget
套件後,要來製作Startup
類別了
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 public class Startup { public IConfiguration Configuration { get ; private set ; } public Startup () { var builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json" , optional: false ); var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT" ); if (!string .IsNullOrEmpty(environment)) { builder = builder.AddJsonFile($"appsettings.{environment} .json" , optional: true , reloadOnChange: false ); } this .Configuration = builder.Build(); } public ServiceCollection ConfigureServices () { var serviceCollection = new ServiceCollection(); serviceCollection.AddTransient<App>(); serviceCollection.AddTransient<IPingTestService, PintTestByHttpRequestService>(); return serviceCollection; } }
配置AppSettings 主要是新增各個環境的AppSettings
檔案,這邊主要是要提醒大家,要將新增的appsettings
檔案要去設定Copy always
,筆者以Development
檔案為準,列出筆者這邊的設定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 { "EmailSetting" : { "SmtpServer" : "SMTP Host" , "SmtpPort" : 587 , "Account" : "SMTP Account" , "Password" : "SMTP Password" } , "TestUrl" : "https://google.com.tw" , "MailToDo" : { "MailTo" : "test@gmail.com;test2@gmail.com" , "MailCc" : "" , "Subject" : "Test Subject" } }
LaunchSettings配置 筆者這邊習慣調整LaunchSettings
來切換Development
, Staging
, UAT
等環境,Console Application的專案預設是沒有任何設定的,看不到Properties/LaunchSettings.json
的,就動手加上去吧
加上去後會在Solution Explorer
中會看到LaunchSettings.json
了
製作主要運作程式App類別 基礎建設都用完了,要來撰寫主要執行的App
類別了,邏輯觀念為
從Appsettings
讀取EmailSetting
及Mail
相關設定
宣告MySmtpClient
物件
執行主要Ping Test
程式
若回傳錯誤或者Exception
則寄信通知對應的信箱
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 public class App { private readonly IPingTestService _pingTestService; public App (IPingTestService pingTestService ) { _pingTestService = pingTestService; } public async Task Run (IConfiguration config ) { var emailSetting = config.GetSection("EmailSetting" ).Get<EmailSetting>(); var mailTodo = config.GetSection("MailToDo" ).Get<MailToDoItem>(); var mySmtpClient = new MySmtpClient(mailTodo, emailSetting); mySmtpClient.MySendCompleted += MailSendCompleted; try { var result = await _pingTestService.PingHost(config["TestUrl" ]); if (!result) { mailTodo.Message = "Monitor作業偵測到連線異常通知" ; await mySmtpClient.SendMailProcess(null , null ); } } catch (Exception ex) { mailTodo.Subject = $"Monitor作業異常通知" ; mailTodo.Message = $"{ex} " ; await mySmtpClient.SendMailProcess(null , null ); } } private void MailSendCompleted (MailToDoItem mailToDoItem, AsyncCompletedEventArgs e ) { } }
上述程式中用到的MySmtpClient
、EmailSetting
、MailToDoItem
類別宣告就不特別在此列出,可以參考筆者這篇文章
[DotnetCore]SMTP寄信服務設計
Program:Main程式 最後要來撰寫Main
程式了,直接用Code
說話
1 2 3 4 5 6 7 8 9 10 11 12 class Program { public static async Task Main (string [] args ) { var startUp = new Startup(); var serviceProvider = startUp.ConfigureServices().BuildServiceProvider(); var app = serviceProvider.GetRequiredService<App>(); await app.Run(startUp.Configuration); } }
結論 藉由這次,平常直接透過dotnet new webapi
這種指令建置出Web API
專案,基本上那些相關的設定都配置好了,這次撰寫過程,就會知道,之所以可以使用IConfiguration
則,需要安裝哪些套件,DI
注入宣告之ServiceCollection
需要的是哪個對應的nuget
套件,對於筆者來說,是滿大的收穫。
參考