只有累積,沒有奇蹟

2019年5月15日 星期三

[NETCore] ASP.NET Core 3.0 Preview 體驗

前言
ASP.NET Core 3.0 preview 5 已經推出,在 3.0 最大的變化是對 windows desktop application 的支援,
以及支援 .NET Standard 2.1 和可以在 Visual Studio 2019 上使用 C# 8.0 功能,這篇文章紀錄安裝 ASP.NET Core 3.0 SDK 以及 升級 Visual Studio 2019 Update,若有問題或是錯誤的地方歡迎提出來一起討論。


Visual Studio 2019 
經過一段時間的 preview 與測試,VS 2019 在 2019 年 4 月開放下載,如果沒有安裝 Visual Studio 2019 可以到官方網站下載
  • Community : 傳送門
  • Professional :  傳送門
  • EnterPrise :  傳送門

  • 在 Visual Studio 2019 提供許多好用的新功能,Visual Studio 2019 的新功能 官網文章整理詳細及新功能介紹,有興趣了解的可以透過文章及影片內容深入了解,個人整理重點如下

  • IntelliCode : 搜尋在 GitHub 上超過 2000 顆星的 open source project 進行訓練提供開發時建議
  • 重構 : 按下 Ctrl+.,會針對此段程式碼提出重構的建議
  • Live Share : 可以跟朋友同時在 IDE 一起閱讀、開發及針對現有程式碼進行除錯
  • 偵錯時搜尋 : 偵錯時可以針對加入的變數進行關鍵字搜尋
  • 快速搜尋 : Ctrl+Q 快速搜尋支援模糊搜尋
  • 程式碼清除 : 根據所設定的格式進行程式碼的整理 
  • 新的啟動介面 : 新的啟動介面,可以更快的建立專案以及 fork Git source code 

  • 升級 Visual Studio 2019
    手邊的開發筆電 VS2019 為最早的版本,因此如果要使用 ASP.NET Core 3.0 的話官方建議需要更新 Visual Studio 最新版才可使用,可以透過 選單 > Help > Check for update 查看目前版本升級,更新畫面如下

    .NET Core 3.0  
    安裝 / 升級 Visual Studio 2019 後還需安裝 .NET Core 3.0 SDK ,如果開始使用 ASP.NET Core 3.0 preview 則需要安裝相對應的 SDK : 下載傳送門 ,
    當完成 Visual Studio 2019 升級也安裝所需要的 ASP.NET Core 3.0 SDK,接著開啟 VS2019 新增專案,發現 Platform 選項中最新只到 2.2 並沒有稍早安裝的 3.0 ? 
    莫急莫慌莫害怕,不是因為沒裝好或是安裝步驟出問題,原因是因為在過去如果安裝新的 SDK Preview 版本時,Visual Studio 工具都會使用新的 SDK 為主,可能會造成相容性的問題發生,為了改善這問題從 Visual Studio 2017 15.9 版本開始,Visual Studio 工具都預設會以穩定的 SDK 版本為主(也就是 Preview 的不會出現),如果有安裝 Preview 的 SDK 時可以透過設定進行調整,設定方式為 Projects and Solutions > .NET Core > 勾選 Use previews of the NET Core SDK
    設定完畢之後,在重新開啟 Visual Studio 就可以看到可以選擇 ASP.NET Core 3.0 選單
    另外也可以觀察到在選擇 .NET Core 2.2 與 .NET Core 3.0 時版本會有所差異,在新增 Web Application 選擇 .NET Core 3.0 樣板會多下列項目
  • gRPC Service
  • Blazor (Service Side)
  • Razor Class Library 

  • gRPC 是 Google 推出的新式高效能輕量型 RPC 架構;Blazor 則是 C# 結合 WebAssembly 的技術,詳細可以參考 ASP.NET Core 上的 gRPC 簡介 說明。

    C# 8.0
    ASP.NET Core 3.0 支援 C# 8.0 語法,在更新完 Visual Studio 2019 至最新版以及安裝完 .NET Core 3.0 SDK 後可以在 Visual Studio IDE 進行設定,設定步驟如下
    Step 1 : Project > Properties
    Step 2 : 左邊 Tab 選擇 Build
    Step 3 : Advance > Language version
    對於 C# 8.0 新增的改變有興趣可以看官網 MSDN 介紹,What's new in C# 8.0
    由於自己尚未接觸過這部分,日後如果有實際使用過會在分享相關的代碼 :)

    最後,附上影片 Visual Studio 2019 Launch: What’s Coming with .NET Core 3.0 結束這篇介紹,期待 3.0 正式 Release 的一天 :)

    參考
    .NET Core tooling update for Visual Studio 2017 version 15.9
    .NET Core 3.0, VS2019 and C# 8.0 for ASP .NET Core developers
    Quick Tip: How to Try .NET Core 3.0 in Visual Studio 2019
    Creating First ASP.NET Core 3.0 App with Visual Studio 2019 Preview

    2019年5月14日 星期二

    [NETCore] ASP.NET Core 啟動異常 - HTTP Error 500.30 - ANCM In-Process Start Failure

    問題 
    在開發專案時跳出異常訊息,錯誤訊息為  HTTP Error 500.30 - ANCM In-Process Start Failure ,這篇就針對此案例作簡單紀錄與分享,若是有不清楚或是錯誤的地方歡迎討論予糾正。

    解決方法 
    廢話不多說,先看案發現場的錯誤畫面
    執行異常的程式代碼,看起來很單純的代碼
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }
    
    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
               
    
    在錯誤訊息中提到應用程式無法啟動可能是因為 Application 啟動失敗、或是啟動時發生異常造成,建議解決方案為開啟事件檢視器進行確認,因此照著建議的除錯步驟找出問題的發生點

    事件檢視器
    開啟事件檢視器發現啟動 Application 時有多筆異常原因,過濾後有幫助的訊息如下
    可以看到事件檢視器錯誤訊息為  Application '/LM/W3SVC/2/ROOT' with physical root 'D:\Marcus\git\SerilogWebAppLab\SerilogWebAppLab\SerilogWebAppLab\' hit unexpected managed exception, exception code = '0xe0434352'. Please check the stderr logs for more information. ,其中提到 exception code 為 0xe0434352,在 How do I fix a .NET windows application crashing at startup with Exception code: 0xE0434352 文章中提到此錯誤代碼為 .NET 在執行中異常的代碼,因此錯誤訊息也建議透過 stderr 紀錄來查看更多訊息 (一直挖挖挖蒐集麵包屑的概念),接著下一步是確認 stderr 相關 Log 紀錄。

    ASP.NET Core Module stdout log
    在 ASP.NET Core 中 stdout log 預設是關閉的,可以透過 Web.config 設定  stdoutlogEnable  開啟,如下
    <aspNetCore processPath="dotnet"
          arguments=".\MyApp.dll"
          stdoutLogEnabled="true"
          stdoutLogFile=".\logs\stdout"
          hostingModel="InProcess"> 
    stdoutLogEnabled 為啟用 stdout 紀錄,stdoutLogFile 是設定輸出 Log 路徑。如果是使用 Visual Studio IDE 使用 IIS Express 執行的話,則可以到專案檔底下的隱藏資料夾中的 applicationhost.config 搜尋 aspNetCore 區塊設定
    ProjectName\.vs\ProjectName\config\applicationhost.config
    修改後儲存 Web.config 檔案,重新執行一次應用程式,可以看到專案底下 Log 資料夾有新增指定檔案
    檔名前面為 stdout 開頭,後面為時間戳記及處理事件代碼
    stdout_20190513222912_28664.log
    開啟 Log 檔案,內容顯示無法 Application 啟動時異常原因
    透過 stdout Log 得知異常原因為 CreateDefaultBuilder 方法時預設會去讀取 appsettings.json 檔案,但由於 json 檔案格式錯誤造成 application 啟動時無法正常啟動,因而顯示 HTTP error 500.30 的狀況發生,修正後即可正常執行,宣告除蟲成功 ! 

    備註 : Troubleshoot ASP.NET Core on IIS 內文有提到因為沒有限制記錄檔大小或是數量上限,啟用可能會造成應用程式或是伺服器失敗,請在確認完畢後關閉  stdoutlogEnable  為 false。

    Improve 
    調整代碼在啟動時加上 try catch 記錄錯誤訊息,讓之後遇到同樣事情可以更快發現 :)
    public class Program
    {
        public static void Main(string[] args)
        {
            InitialSerilog();
    
            try
            {
                CreateWebHostBuilder(args).Build().Run();
            }
            catch (Exception e)
            {
                Log.Error(e.Message);
                throw;
            }
        }
    
        private static void InitialSerilog()
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Information()
                .WriteTo.Console()
                .WriteTo.File("logs/log_.txt", rollingInterval: RollingInterval.Day)
                .CreateLogger();
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }

    參考

    2019年5月13日 星期一

    [NETCore] 在 ASP.NET Core Web API 中使用 Serilog

    前言
    近期專案都在嘗試 Serilog,對於使用上有點小小心得,因此整理這篇文章分享 Serilog 在 ASP.NET Core API 上的使用與設定,也接續之前 Serilog 的系列介紹文 : 傳送門 的實際應用心得,希望可以幫到有需要的朋友,若有問題或是錯誤的地方歡迎提出來一起討論或是給予指導。

    ASP.NET Core logging
    首先先建立新的 ASP.NET Core Web Application 專案,開啟 Visual Studio 2019 選擇建立新專案,專案名稱輸入 SerilogWebAppLab,模板部分選擇 API,然後按下確定送出
    新增完專案之後,可以看到專案中 program.cs 內建 CreateWebHostBuilder 方法,此方法會在 Application 啟動時,使用預設方法也會一併註冊內建 logging,接著我們來看一下內建 logging 輸出樣式,在 ValueController 中建構式加入 _Logger 並在 GET 方法中使用 log.Information、Warning 以及 Error
    public class ValuesController : ControllerBase
    {
        private readonly ILogger _logger;
    
        public ValuesController(ILogger<ValuesController> logger)
        {
            _logger = logger;
        }
    
        // GET api/values
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            _logger.LogInformation("This is LogInformation");
            _logger.LogWarning("This is LogWarning");
            _logger.LogError("This is LogError");
    
            return new[] { "value1", "value2" };
        }
    ...
    執行專案按下 F5,輸出內容如下
    從預設 logging 內容可以發現紀錄了除了自己紀錄的 log 之外資料,紀錄了 Application 以及 Request 的內容還有執行的時間,CreateWebHostBuilder 方法預設的情況下使用的 Config 為專案檔底下的 appsettings.json 及 appsettings.Development.json (依設定環境決定),之前有撰寫過一篇關於設定環境變數的文章,有興趣可以參考 : 傳送門。在此如果希望不啟用內建的 logging 紀錄資訊,可以在 CreateWebHostBuilder 方法中加上  config.ClearProviders()  刪除預設的 logging 提供者
    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureLogging((hostingContext, config) =>
            {
                config.ClearProviders();
            })
            .UseStartup<Startup>();
    在重新執行一次 Application,就會看到 Console output 僅剩三個 log。

    Serilog
    接著輪到今天的重頭戲 Serilog 登場,首先先透過 Nuget 下載 Serilog for .NET Core 套件
    Install-Package Serilog.AspNetCore
    Serilog 核心負責紀錄 Log 事件的內容,要將 Log 輸出則是透過 Sink,如果想瞭解更多細節可以參考 結構化日誌 Serilog 初體驗,這裡就不在多加介紹,這裡範例是使用 Console 與寫入實體檔案作為輸出,因此需要另外透過 Nuget 下載相關套件 Sinks.Console 與 Sinks.File 兩種,如果有其他需
    Install-Package Serilog.Sinks.Console 
    Install-Package Serilog.Sinks.File
    
    下載完 Serilog 相關 Package,接著就是在 WebHost 啟動時設定 Serilog 資訊也就是 Program.cs 中的 main 方法加下以下代碼
    public class Program
    {
        public static void Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Information()
                .WriteTo.Console()
                .WriteTo.File("logs/log_.txt", rollingInterval: RollingInterval.Day)
                .CreateLogger();
    
            CreateWebHostBuilder(args).Build().Run();
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureLogging((hostingContext, config) =>
                {
                    config.ClearProviders();
                })
                .UseStartup<Startup>();
    }
    程式說明

  • MinimumLevel.Information : 定義 Log 輸出 Level 
  • WriteTo.Console : 設定使用 Console 輸出 
  • WriteTo.File : 設定使用 File 檔案輸出,輸出位置及檔名為 log & log_txt 
  • 上述是在 Program.cs 中加上 Serilog 設定組態設定,在 Serilog 中也支援使用 Config 檔案來設定的動作,如果想要透過定義檔則需要至 Nuget 下載 Settings library
    Install-Package Serilog.Settings.Configuration
    在 appSettings.json 加以下 config 定義內容,設定目的與內容與剛剛在 Program 寫 Log 方式相同
    {
      "Serilog": {
        "MinimumLevel": "Information",
        "WriteTo": [
          {
            "Name": "Console",
            "Args": {
              "outputTemplate": "{Timestamp:yyyy/MM/dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"
            }
          },
          {
            "Name": "File",
            "Args": {
              "Path": "logs/log_.txt",
              "rollingInterval": "Day"
            }
          }
        ]
      }
    }
    在來修改 Program.cs 中的代碼,要調整新增 Configuration 時以檔案的內容為主
    public class Program
    {
        private static string _envName;
        public static void Main(string[] args)
        {
            var configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json")
                .AddJsonFile($"appsettings.{_envName}.json", optional: true, reloadOnChange: true)
                .Build();
    
            Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(configuration)
                .CreateLogger();
    
            CreateWebHostBuilder(args).Build().Run();
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureLogging((hostingContext, config) =>
                {
                    config.ClearProviders();
                    _envName = hostingContext.HostingEnvironment.EnvironmentName;
                })
                .UseStartup<Startup>();
    }
    configuration 部分代碼為定義設定檔的來源,也就是使用建立專案時內建的 appsettings.json,指定 Config 會隨不同環境取得不同的 appsettings.json,其中 CreateLogger 時用  ReadFrom.Configuation()  指定用 檔案內容指定取代原先落落長的代碼。
    下一步就需要在 Startup.cs 中的  ConfigureService()  新增 Serilog 至服務中,這裡使用的是內建的 DI Framework,如果用習慣 Autofac 的朋友也可以下載 autofac-serilog-integration,
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        services.AddLogging(loggingBuilder =>
            loggingBuilder.AddSerilog()
        );
    }
    以上設定 Serilgo 完畢,接著重新執行 Application 並觀察其輸出內容,可以看到 logging 紀錄內容已透過 Console 與檔案輸出如下
    也成功寫入檔案,預設會在指定檔名 File 後加上 日期,log_ 變成 log_20190101.txt 
    2019-05-13 13:00:06.279 +08:00 [INF] User profile is available. Using 'C:\Users\marcustung\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.
    2019-05-13 13:00:08.112 +08:00 [INF] Request starting HTTP/1.1 GET https://localhost:5001/api/values  
    2019-05-13 13:00:08.178 +08:00 [INF] Executing endpoint 'SerilogWebAppLab.Controllers.ValuesController.Get (SerilogWebAppLab)'
    2019-05-13 13:00:08.202 +08:00 [INF] Route matched with {action = "Get", controller = "Values"}. Executing action SerilogWebAppLab.Controllers.ValuesController.Get (SerilogWebAppLab)
    2019-05-13 13:00:08.216 +08:00 [INF] Executing action method SerilogWebAppLab.Controllers.ValuesController.Get (SerilogWebAppLab) - Validation state: "Valid"
    2019-05-13 13:00:08.221 +08:00 [INF] This is LogInformation
    2019-05-13 13:00:08.222 +08:00 [WRN] This is LogWarning
    2019-05-13 13:00:08.224 +08:00 [ERR] This is LogError
    2019-05-13 13:00:08.230 +08:00 [INF] Executed action method SerilogWebAppLab.Controllers.ValuesController.Get (SerilogWebAppLab), returned result Microsoft.AspNetCore.Mvc.ObjectResult in 5.7992ms.
    2019-05-13 13:00:08.240 +08:00 [INF] Executing ObjectResult, writing value of type 'System.String[]'.
    2019-05-13 13:00:08.340 +08:00 [INF] Executed action SerilogWebAppLab.Controllers.ValuesController.Get (SerilogWebAppLab) in 131.7199ms
    2019-05-13 13:00:08.344 +08:00 [INF] Executed endpoint 'SerilogWebAppLab.Controllers.ValuesController.Get (SerilogWebAppLab)'
    2019-05-13 13:00:08.351 +08:00 [INF] Request finished in 245.3211ms 200 application/json; charset=utf-8
    成功紀錄 Log 在 Console 與 File 檔案,如果想要的輸出不只是檔案在 Serilog 提供多種 Provider,詳細可以參考官方網站所列的 Provided Sinks : 傳送門。

    感想
    透過以上的說明,希望可以讓對 Serilog 有興趣的的朋友可以快速入門,之前也花了點時間介紹 Serilog 相關的入門 & 基本設定方式,若有興趣想了解細節的也可以了解看看,系列文連結 : 傳送門 :)

    參考
    Structured logging concepts in .NET Series
    Serilog series post
    Loggly in ASP.NET Core using Serilog

    Copyright © m@rcus 學習筆記 | Powered by Blogger

    Design by Anders Noren | Blogger Theme by NewBloggerThemes.com