2021年4月7日 星期三

在 Blazor 專案內使用 NLog 進行系統執行日誌紀錄

在 Blazor 專案內使用 NLog 進行系統執行日誌紀錄

在這篇文章中,將要來學習如何在 ASP.NET Core 專案內使用第三方 NLog 日誌套件,協助進行該專案執行過程中的相關重要訊息紀錄。

首先,在 ASP.NET Core 開發環境內,已經預設具備了訊息日誌能力,這部分可以參考 .NET Core 與 ASP.NET Core 中的記錄 說明文章,要能夠知道各種 ASP.NET Core 中的紀錄程式設計方式、設定、宣告方式。

現在,就來開始實際建立一個 Blazor 專案,看看 NLog 如何在 Blazor 專案中使用情況。

這篇文章的原始碼位於 bzNlog

建立測試用主控台應用程式專案

  • 開啟 Visual Studio 2019
  • 選擇右下方的 [建立新的專案] 按鈕
  • 在 [建立新專案] 對話窗中
  • 從右上方的專案類型下拉按鈕中,找到並選擇 [Web]
  • 從可用專案範本清單內,找到並選擇 [Blazor Server 應用程式]
  • 點選左下方 [下一步] 按鈕
  • 在 [設定新的專案] 對話窗中
  • 在 [專案名稱] 欄位中輸入 bzNlog
  • 點選左下方 [下一步] 按鈕
  • 在 [其他資訊] 對話窗中
  • 在 [目標 Framework] 下拉選單中,選擇 [.NET 5.0 (目前)]
  • 點選左下方 [建立] 按鈕

加入所需要使用到的 NuGet 套件

  • 滑鼠右擊 [bzNlog] 專案內的 [相依性] 節點
  • 從彈出功能表中,選擇 [管理 NuGet 套件]
  • 當 [NuGet: bzNlog] 視窗出現後,切換到 [瀏覽] 標籤頁次
  • 搜尋 [NLog.Web.AspNetCore] 並且安裝並且套件
  • 安裝完成後,會有一個 [readme.txt] 視窗顯示出來,提示如何使用
Welcome to NLog for ASP.NET Core!

To get started, check one of these short tutorials:

- Getting started for ASP.NET Core 5: https://github.com/NLog/NLog/wiki/Getting-started-with-ASP.NET-Core-5
- Getting started for ASP.NET Core 3: https://github.com/NLog/NLog/wiki/Getting-started-with-ASP.NET-Core-3
- Getting started for ASP.NET Core 2: https://github.com/NLog/NLog/wiki/Getting-started-with-ASP.NET-Core-2

# More information

- How to use structured logging: https://github.com/NLog/NLog/wiki/How-to-use-structured-logging
- All config options: https://nlog-project.org/config

# Troubleshooting

Having issues to get things working? It's recommend to follow to Troubleshooting https://github.com/NLog/NLog/wiki/Logging-troubleshooting page.

For questions, StackOverflow (https://stackoverflow.com/questions/tagged/nlog) is recommend

建立 nlog.config 設定檔案

  • 滑鼠右擊 [bzNlog] 專案節點
  • 選擇 [加入] > [新增項目]
  • 此時將會顯示 [新增項目] 對話窗
  • 在左邊請點選 [已安裝] > [Visual C#] > [ASP.NET Core] > [資料]
  • 在該對話窗的中間部分,請選擇 [XML檔]
  • 在下方 [名稱] 欄位,輸入 nlog.config
  • 將底下內容填入到這個檔案內
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      throwConfigExceptions="true"
      internalLogLevel="info"
      internalLogFile="c:\temp\internal-nlog-AspNetCore5.txt">

	<!-- enable asp.net core layout renderers -->
	<extensions>
		<add assembly="NLog.Web.AspNetCore"/>
	</extensions>

	<!-- the targets to write to -->
	<targets>
		<!-- File Target for all log messages with basic details -->
		<target xsi:type="File" name="allfile" fileName="c:\temp\nlog-AspNetCore5-all-${shortdate}.log"
				layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" />

		<!-- File Target for own log messages with extra web details using some ASP.NET core renderers -->
		<target xsi:type="File" name="ownFile-web" fileName="c:\temp\nlog-AspNetCore5-own-${shortdate}.log"
				layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}|" />

		<!--Console Target for hosting lifetime messages to improve Docker / Visual Studio startup detection -->
		<target xsi:type="Console" name="lifetimeConsole" layout="${level:truncate=4:lowercase=true}: ${logger}[0]${newline}      ${message}${exception:format=tostring}" />
	</targets>

	<!-- rules to map from logger name to target -->
	<rules>
		<!--All logs, including from Microsoft-->
		<logger name="*" minlevel="Trace" writeTo="allfile" />

		<!--Output hosting lifetime messages to console target for faster startup detection -->
		<logger name="Microsoft.Hosting.Lifetime" minlevel="Info" writeTo="lifetimeConsole, ownFile-web" final="true" />

		<!--Skip non-critical Microsoft logs and so log only own logs-->
		<logger name="Microsoft.*" maxlevel="Info" final="true" />
		<!-- BlackHole -->

		<logger name="*" minlevel="Trace" writeTo="ownFile-web" />
	</rules>
</nlog>

設定 nlog.config 設定檔案屬性

  • 在方案總管中找到這個 [nlog.config] 檔案

  • 請在 [屬性] 視窗中找到 [複製到輸出目錄] 這個欄位

  • 設定 [複製到輸出目錄] 的設定值為 [有更新時才複製]

    nlog.config 複製到輸出目錄設定值

更新 program.cs

  • 在方案總管中找到這個 [program.cs] 檔案
  • 打開這個 [program.cs] 檔案
  • 底下為現在的程式碼內容
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace bzNlog
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}
  • 修正成為底下程式碼,讓 NLog 可以正常運作
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog.Web;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace bzNlog
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
            try
            {
                logger.Debug("NLog 系統日誌開始初始化");
                CreateHostBuilder(args).Build().Run();
            }
            catch (Exception exception)
            {
                //NLog: catch setup errors
                logger.Error(exception, "因為遇到無法處理的例外異常,所以,程式停止執行");
                throw;
            }
            finally
            {
                // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
                NLog.LogManager.Shutdown();
            }
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                })
            .ConfigureLogging(logging =>
            {
                logging.ClearProviders();
                logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
            })
            .UseNLog();  // NLog: Setup NLog for Dependency injection;
    }
}

修正 appsettings.json

  • 在專案根目錄下找到 [appsettings.json] 檔案
  • 修正為底下內容
{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Trace",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}
  • 在專案根目錄下找到 [appsettings.Development.json] 檔案
  • 修正為底下內容
{
  "DetailedErrors": true,
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Trace",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

開始使用 日誌紀錄 功能

  • 在 Blazor 專案內,找到 [Pages] 資料夾
  • 打開 [Counter.razor] 檔案
  • 修正成為底下程式碼
@page "/counter"
@using Microsoft.Extensions.Logging;
@inject ILogger<Counter> logger;

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<div>
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</div>
<div>
    <button class="btn btn-danger" @onclick="RaiseException">拋出例外異常</button>
</div>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
        logger.LogInformation($"計數器按鈕已經被按下! Counter={currentCount}");
    }
    private void RaiseException()
    {
        Exception exception = new Exception("喔喔,遇到例外異常");
        throw exception;
    }
}

執行並且測試

  • 按下 F5 開始執行這個專案

  • 網頁出現之後,請點選左邊的 [Counter] 按鈕

  • 現在將會看到底下的畫面

  • 請點選數次 [Counter] 按鈕

  • 最後點選紅色的 [拋出例外異常] 按鈕

  • 當然此時這個 Blazor 頁面會顯示有無法預期的例外異常產生出來

  • 使用 [檔案總管] 打開 [C:\Temp] 目錄

  • 將會看到有三個檔案產生

  • 底下分別是這三個檔案的內容

  • internal-nlog-AspNetCore5.txt

2021-03-24 14:01:33.0315 Info Message Template Auto Format enabled
2021-03-24 14:01:33.0506 Info Loading assembly: NLog.Web.AspNetCore
2021-03-24 14:01:33.1166 Info Adding target FileTarget(Name=allfile)
2021-03-24 14:01:33.1307 Info Adding target FileTarget(Name=ownFile-web)
2021-03-24 14:01:33.1307 Info Adding target ConsoleTarget(Name=lifetimeConsole)
2021-03-24 14:01:33.1849 Info Validating config: TargetNames=allfile, lifetimeConsole, ownFile-web, ConfigItems=67, FilePath=D:\Vulcan\GitHub\CSharp2021\bzNlog\bzNlog\bin\Debug\net5.0\nlog.config
  • nlog-AspNetCore5-all-2021-03-24.log
2021-03-24 14:01:33.2446|0|DEBUG|bzNlog.Program|NLog 系統日誌開始初始化 
2021-03-24 14:01:35.3760|0|INFO|Microsoft.Hosting.Lifetime|Now listening on: https://localhost:5001 
2021-03-24 14:01:35.4007|0|INFO|Microsoft.Hosting.Lifetime|Now listening on: http://localhost:5000 
2021-03-24 14:01:35.4150|0|INFO|Microsoft.Hosting.Lifetime|Application started. Press Ctrl+C to shut down. 
2021-03-24 14:01:35.4258|0|INFO|Microsoft.Hosting.Lifetime|Hosting environment: Development 
2021-03-24 14:01:35.4258|0|INFO|Microsoft.Hosting.Lifetime|Content root path: D:\Vulcan\GitHub\CSharp2021\bzNlog\bzNlog 
2021-03-24 14:01:54.5580|0|INFO|bzNlog.Pages.Counter|計數器按鈕已經被按下! Counter=1 
2021-03-24 14:01:54.8048|0|INFO|bzNlog.Pages.Counter|計數器按鈕已經被按下! Counter=2 
2021-03-24 14:01:55.0641|0|INFO|bzNlog.Pages.Counter|計數器按鈕已經被按下! Counter=3 
2021-03-24 14:01:55.3102|0|INFO|bzNlog.Pages.Counter|計數器按鈕已經被按下! Counter=4 
2021-03-24 14:01:55.5468|0|INFO|bzNlog.Pages.Counter|計數器按鈕已經被按下! Counter=5 
2021-03-24 14:01:55.8066|0|INFO|bzNlog.Pages.Counter|計數器按鈕已經被按下! Counter=6 
2021-03-24 14:02:00.5067|100|WARN|Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer|Unhandled exception rendering component: 喔喔,遇到例外異常 System.Exception: 喔喔,遇到例外異常
   at bzNlog.Pages.Counter.RaiseException() in D:\Vulcan\GitHub\CSharp2021\bzNlog\bzNlog\Pages\Counter.razor:line 27
   at Microsoft.AspNetCore.Components.EventCallbackWorkItem.InvokeAsync[T](MulticastDelegate delegate, T arg)
   at Microsoft.AspNetCore.Components.ComponentBase.Microsoft.AspNetCore.Components.IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, Object arg)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.DispatchEventAsync(UInt64 eventHandlerId, EventFieldInfo fieldInfo, EventArgs eventArgs)
2021-03-24 14:02:00.5859|111|ERROR|Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost|Unhandled exception in circuit 'gVHXSluIzW3bY7wbiTH5wcsJGHO-Y9VsSwBxMn0Cots'. System.Exception: 喔喔,遇到例外異常
   at bzNlog.Pages.Counter.RaiseException() in D:\Vulcan\GitHub\CSharp2021\bzNlog\bzNlog\Pages\Counter.razor:line 27
   at Microsoft.AspNetCore.Components.EventCallbackWorkItem.InvokeAsync[T](MulticastDelegate delegate, T arg)
   at Microsoft.AspNetCore.Components.ComponentBase.Microsoft.AspNetCore.Components.IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, Object arg)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.DispatchEventAsync(UInt64 eventHandlerId, EventFieldInfo fieldInfo, EventArgs eventArgs)
  • nlog-AspNetCore5-own-2021-03-24.log
2021-03-24 14:01:33.2446|0|DEBUG|bzNlog.Program|NLog 系統日誌開始初始化 |url: |action: |
2021-03-24 14:01:35.3760|0|INFO|Microsoft.Hosting.Lifetime|Now listening on: https://localhost:5001 |url: |action: |
2021-03-24 14:01:35.4007|0|INFO|Microsoft.Hosting.Lifetime|Now listening on: http://localhost:5000 |url: |action: |
2021-03-24 14:01:35.4150|0|INFO|Microsoft.Hosting.Lifetime|Application started. Press Ctrl+C to shut down. |url: |action: |
2021-03-24 14:01:35.4258|0|INFO|Microsoft.Hosting.Lifetime|Hosting environment: Development |url: |action: |
2021-03-24 14:01:35.4258|0|INFO|Microsoft.Hosting.Lifetime|Content root path: D:\Vulcan\GitHub\CSharp2021\bzNlog\bzNlog |url: |action: |
2021-03-24 14:01:54.5580|0|INFO|bzNlog.Pages.Counter|計數器按鈕已經被按下! Counter=1 |url: https://localhost/_blazor|action: |
2021-03-24 14:01:54.8048|0|INFO|bzNlog.Pages.Counter|計數器按鈕已經被按下! Counter=2 |url: https://localhost/_blazor|action: |
2021-03-24 14:01:55.0641|0|INFO|bzNlog.Pages.Counter|計數器按鈕已經被按下! Counter=3 |url: https://localhost/_blazor|action: |
2021-03-24 14:01:55.3102|0|INFO|bzNlog.Pages.Counter|計數器按鈕已經被按下! Counter=4 |url: https://localhost/_blazor|action: |
2021-03-24 14:01:55.5468|0|INFO|bzNlog.Pages.Counter|計數器按鈕已經被按下! Counter=5 |url: https://localhost/_blazor|action: |
2021-03-24 14:01:55.8066|0|INFO|bzNlog.Pages.Counter|計數器按鈕已經被按下! Counter=6 |url: https://localhost/_blazor|action: |
2021-03-24 14:02:00.5067|100|WARN|Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer|Unhandled exception rendering component: 喔喔,遇到例外異常 System.Exception: 喔喔,遇到例外異常
   at bzNlog.Pages.Counter.RaiseException() in D:\Vulcan\GitHub\CSharp2021\bzNlog\bzNlog\Pages\Counter.razor:line 27
   at Microsoft.AspNetCore.Components.EventCallbackWorkItem.InvokeAsync[T](MulticastDelegate delegate, T arg)
   at Microsoft.AspNetCore.Components.ComponentBase.Microsoft.AspNetCore.Components.IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, Object arg)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.DispatchEventAsync(UInt64 eventHandlerId, EventFieldInfo fieldInfo, EventArgs eventArgs)|url: https://localhost/_blazor|action: |
2021-03-24 14:02:00.5859|111|ERROR|Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost|Unhandled exception in circuit 'gVHXSluIzW3bY7wbiTH5wcsJGHO-Y9VsSwBxMn0Cots'. System.Exception: 喔喔,遇到例外異常
   at bzNlog.Pages.Counter.RaiseException() in D:\Vulcan\GitHub\CSharp2021\bzNlog\bzNlog\Pages\Counter.razor:line 27
   at Microsoft.AspNetCore.Components.EventCallbackWorkItem.InvokeAsync[T](MulticastDelegate delegate, T arg)
   at Microsoft.AspNetCore.Components.ComponentBase.Microsoft.AspNetCore.Components.IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, Object arg) 

   at Microsoft.AspNetCore.Components.RenderTree.Renderer.DispatchEventAsync(UInt64 eventHandlerId, EventFieldInfo fieldInfo, EventArgs eventArgs)| 










2021年4月3日 星期六

2021年04月 .NET 平行程式設計介紹 免費課程

2021年04月 .NET 平行程式設計介紹 免費課程

.NET 平行程式設計介紹 免費課程

課程名稱

.NET 平行程式設計介紹

課程介紹

平行程式設計是很早以前就存在的一個設計方式,隨著電腦處理器數量不斷的增加,更加凸顯這門技術的重要性,也是絕大部分程式設計師夢幻的開發技術,它可以提升整體應用程式的執行效能與改善流暢反應的使用者體驗;不過,平行程式設計也存在著以難以理解與複雜設計方法而著名,讓許多程式設計師無法輕鬆駕馭這個設計方法。

在這個技術分享課程中,首先會透過一個範例專案,讓大家體會到非同步/平行技術所帶來的好處與想要解決的問題,緊接著將會帶領大家一窺 .NET 開發環境中的各種非同步程式設計技術有哪些設計模式,並且了解 .NET 提供了可以用於平行計算的原理與相關 API;這些內容將會透過一個使用同步設計的專案來開始,逐步使用各種 .NET 提供的非同步/平行設計技術,明瞭到如何使用這些非同步/平行開發技術來完成同樣使用同步方式所設計的專案程式碼,並且知道整體上改善了多少執行效能。

透過本課程的介紹,可以程式開發人員具備了非同步/平行相關知識,與實際操作這些程式碼開如何設計出來,當然,也能夠發現到整體的應用程式執行效能與總處理量徹底的大幅提升與設計出具有流暢反應應用程式。

本課程將會涵蓋底下主題

同步 Synchronous 與非同步 Asynchronous 程式設計、平行 Parallelism 與並行 Concurrency 計算、執行緒 Thread、多執行緒、執行緒集區 ThreadPool、工作 Task 程式設計、用 APM、EAP、TAP 非同程式設計、用 async await 做出以同步方式來設計非同步應用需求、常見早期非同步程式設計 Timer BackgroundWorker、平行資料 Parallel.For Parallel.Foreach、平行查詢 PLINQ 處理程式設計

參加條件

  • 具備 C# 程式語言開發經驗
  • 了解泛型、委派、Lambda的使用方式
  • 擁有基本電腦架構運作知識
  • 對多執行緒開發有興趣
  • 能夠熱情參與課程互動
  • 具有 .NET Core 開發環境(VS4W / VS Code / VS4M 皆可)

報名方式

  • 請先使用該 表單 填寫報名資訊與對課程期望
  • 或者掃描底下 QRCode,填寫

202104 .NET 平行程式設計介紹_ 課程報名申請表

  • 請注意,填寫送出本問卷,並不代表可以參加此課程,因為座位有限,若可以參加本免費課程者,將會透過 FB 私訊通知也會於 FB  Xamarin Blazor 實驗室  公告相關訊息

開課時間

2021.04.24 (六) 下午 13:00 ~ 16:00

上課地點

高雄市鼓山區大順一路439號6樓之3 地圖

(凹子底捷運站1號出口,在大順路與博愛路的彰化銀行樓上)

課程費用

免費

其他說明

  • 本課程使用的程式語言為 .NET / C#
  • 預計時間約為3小時
  • 若報名無故沒來參加,將會禁止日後參加本單位舉辦的相關課程
  • 請自行攜帶可以開發與執行 .NET Core 或者 .NET Framework 筆電,進行現場實作練習
  • 該課程以互動提問、討論方式設計,若無法適應此教學方式,請勿報名參加
  • 若有上網需求,請自備可以透過電腦聯網的行動裝置
  • 本課程不提供上課簡報檔案