假設在某個框架中有以下服務:
public interface ICalculationService { int Add( int x, int y); } public class CalculationService : ICalculationService { private readonly ILogger logger; public CalculationService(ILogger logger) => this .logger = logger; public int Add( int x, int y) { var result = x + y; this .logger.LogDebug($ "{x}+{y}={result}" ); return result; } } |
該服務很簡單,就是計算兩個整數的和,併在傳回結果的時候列印一條日誌。如果在ASP.NET Core應用程式中使用這個服務,方法非常簡單,只需要在Startup.cs中註冊服務,然後在Controller中直接透過建構式註入即可:
// Startup.cs public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddSingleton(); } // Controller [Route( "api/[controller]" )] [ApiController] public class CalculationController : ControllerBase { private readonly ICalculationService service; public CalculationController(ICalculationService service) { this .service = service; } [HttpGet( "{x}/{y}" )] public ActionResult< int > Get( int x, int y) => this .service.Add(x, y); } |
執行起來可以看到,日誌可被正常輸出:
那麼,如果希望在一個控制檯應用程式中使用這個CalculationService服務,又該如何提供這個ILogger建構式的引數呢?
在.NET Core控制檯應用程式中,如需使用標準的日誌機制(Microsoft.Extensions.Logging),最合適的做法就是使用依賴註入,透過依賴註入框架來完成ILogger物件的解析。使用標準的日誌機制的一個最大好處是,你可以選擇不同的日誌解決方案,來決定你的應用程式的日誌輸出方式。比如,Serilog提供了非常強大的擴充套件,可以很方便地將Serilog整合到應用程式中,以快速地實現將日誌輸出到幾十種不同的日誌服務平臺。
下麵,我使用dotnet CLI和Visual Studio Code來展示如何在.NET Core控制檯應用程式中,使用上面的CalculationService服務。
首先,在本地目錄中,使用dotnet new命令建立一個控制檯應用程式:
1
|
dotnet new console -n CalcServiceApp |
然後,使用dotnet add命令,新增NuGet包的取用:
dotnet add package Microsoft.Extensions.DependencyInjection dotnet add package Microsoft.Extensions.Configuration dotnet add package Microsoft.Extensions.Configuration.Json dotnet add package Microsoft.Extensions.Logging dotnet add package Microsoft.Extensions.Logging.Configuration dotnet add package Microsoft.Extensions.Logging.Console |
現在,基於CalcServiceApp目錄,啟動Visual Studio Code,如果已經安裝了OmniSharp外掛,Visual Studio Code會自動安裝C#依賴項、更新程式碼取用,並提示會在當前目錄下新建一個.vscode的隱藏目錄,以存放專案除錯的配置資訊。我們暫時還不涉及到除錯的問題,所以可以暫時放一放。
下麵要做的就是在Program類的Main方法中,使用CalculationService提供的服務。Main方法的程式碼如下:
static void Main( string [] args) { // 從appsettings.json檔案中讀入日誌的配置資訊 var configuration = new ConfigurationBuilder() .AddJsonFile( "appsettings.json" ) .Build(); using ( var serviceProvider = new ServiceCollection() .AddLogging(loggingBuilder => { loggingBuilder.AddConfiguration(configuration.GetSection( "Logging" )); loggingBuilder.AddConsole(); // 將日誌輸出到控制檯 }) .AddSingleton() .BuildServiceProvider()) { var calcService = serviceProvider.GetService(); Console.WriteLine(calcService.Add(3, 4)); } } |
上面的程式碼中,透過向ServiceCollection物件新增Logging配置,指定日誌輸出的配置檔案將採用appsettings.json檔案,同時使用該檔案中的Logging節點所提供的配置資訊。目前為了測試,appsettings.json檔案內容如下:
{ "Logging" : { "LogLevel" : { "Default" : "Debug" , "System" : "Information" , "Microsoft" : "Information" } } } |
接下來,就是要確保appsettings.json檔案在程式碼編譯時,能夠正確複製到輸出目錄,以便程式執行時能夠找到該檔案,因此,可以修改專案的csproj檔案,指定appsettings.json檔案能夠在編譯的時候複製到輸出目錄:
< Project Sdk = "Microsoft.NET.Sdk" > < PropertyGroup > < OutputType >Exe < TargetFramework >netcoreapp2.2
< ItemGroup > < PackageReference Include = "Microsoft.Extensions.Configuration" Version = "2.2.0" /> < PackageReference Include = "Microsoft.Extensions.Configuration.Json" Version = "2.2.0" /> < PackageReference Include = "Microsoft.Extensions.DependencyInjection" Version = "2.2.0" /> < PackageReference Include = "Microsoft.Extensions.Logging" Version = "2.2.0" /> < PackageReference Include = "Microsoft.Extensions.Logging.Configuration" Version = "2.2.0" /> < PackageReference Include = "Microsoft.Extensions.Logging.Console" Version = "2.2.0" />
< ItemGroup > < None Update = "appsettings.json" > < CopyToOutputDirectory >Always
|
OK,在命令列透過dotnet run命令啟動應用程式,可以看到日誌能夠被正常輸出:
細心的朋友會發現,為什麼日誌的輸出會在計算結果輸出之後,不是應該在計算的時候才輸出日誌,而此時計算結果還沒有傳回嗎?沒錯,看起來像是日誌的輸出會在單獨的執行緒中進行。如果在Main函式中沒有使用using來合理釋放serviceProvider的資源,那麼日誌的輸出內容會非常奇怪,有時候甚至看不到日誌資訊的輸出。有關這一問題可以參考這篇帖子:https://github.com/aspnet/Logging/issues/631,解決方案就是需要dispose serviceProvider物件,但日誌的輸出仍然是非同步的。
好了,有關在.NET Core控制檯應用程式中使用日誌,就介紹這麼多,有關日誌配置和使用的詳細資訊,可以參考微軟的官方檔案。微軟官方檔案內容非常給力,微軟也花了很大的功夫啟動了Docs專案,來推動檔案本地化的工作行程。本文另一個目的是為了展示使用Visual Studio Code進行.NET Core應用程式的開發,為了撰寫部落格方便,我是在Windows下使用的Visual Studio Code和.NET Core SDK。事實上,在Linux或者MacOS下,都可以很好地使用Visual Studio Code進行.NET應用程式的開發(之前我也有一篇英文文章介紹這個話題:http://sunnycoding.cn/2018/11/07/developing-asp-net-core-apps-by-using-visual-studio-code/)。最後,貼一張Visual Studio Code的圖,供大家參考: