ShowProgramCode

2023年6月14日 星期三

C# Net6 WebAPI或MVC架構下 Nlog+EFCore+MSSQL設定 自動記錄SQL命令

首先建立一個Net6 WebAPI或MVC專案

下面使用WebAPI專案作為示範,不過MVC專案設定大致相同,除了不需要手動增加Model資料夾...

一、設定Nlog

1.使用NuGet管理員,下載NLog.Web.AspNetCore,此次使用版本5.3.0。

2.在專案中手動增加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"
internalLogLevel="Error">
<!-- 啟用 ASP.NET Core layout renderers -->
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<!-- 設定log根目錄 -->
<variable name="logDirectory" value="C:\TWBank_Log\NlogTest" />
<!-- log 儲存目標 -->
<targets>
<target xsi:type="File" name="allfile" fileName="${logDirectory}\nlog-all-${shortdate}.log"
layout="${date:format=HH\:mm\:ss\.ffff} [thread:${threadid}] ${level:uppercase=true} ${message} ${exception:Format=ToString}" createDirs="true" encoding="UTF-8" />
</targets>
<!-- 設定 logger 名稱與 log 儲存目標的對應 -->
<rules>
<!--將Microsoft與System.Net.Http的錯誤拿掉不紀錄-->
<logger name="Microsoft.*" maxlevel="Info" final="true" />
<logger name="System.Net.Http.*" maxlevel="Info" final="true" />
<logger name="*" minlevel="Trace" writeTo="allfile" />
</rules>
</nlog>

3.修改Program.cs

public class Program
{
	public static void Main(string[] args)
	{
		var builder = WebApplication.CreateBuilder(args);

		//將NLog註冊到此專案內
		builder.Logging.ClearProviders();
		builder.Host.UseNLog();

		...
		var app = builder.Build();
		
		...
		app.Run();
	}
}

4.調整appsettings.json

Logging.LogLevel.Default可以控制預設紀錄的Log層級,目前Trace是最低層級,也就是什麼都會記錄。
{
  "Logging": {
    "LogLevel": {
      "Default": "Trace",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

5.修改範本Controller程式碼

Nlog支援將List、物件等,轉換成json string顯示,參考下方程式碼。
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
	IEnumerable<WeatherForecast> temp = Enumerable.Range(1, 5).Select(index => new WeatherForecast
	{
		Date = DateTime.Now.AddDays(index),
		TemperatureC = Random.Shared.Next(-20, 55),
		Summary = Summaries[Random.Shared.Next(Summaries.Length)]
	})
	.ToList();
	_logger.LogDebug("WeatherForecast List = {@temp}", temp);
	return temp;
}

6.確認Log內容

二、設定EFCore,此處設定MSSQL,如果要設定不同資料庫,下載與設定方式會略有不同。

1.使用NuGet管理員,下載EFCore。

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Sqlite

2.手動增加Model資料夾,並在內部加入MyDbContext繼承DbContext

public class MyDbContext: DbContext
{
	public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
	{
	}
	public DbSet<TestUser> User { get; set; }
}

[Table("TestUser")]
public class TestUser
{
	[Key]
	public int Id { get; set; }
	[Required]
	[StringLength(20)]
	public string Name { get; set; } = string.Empty;
	[Required]
	[StringLength(15)]
	public string Phone { get; set; } = string.Empty;
}

3.修改appsettings.json

設定遠端資料庫連線。
開發期間資料庫證書無法設定時,可以添加這個設定,TrustServerCertificate=true,將無條件信任IIS預設證書。
此外,還需要加上Logging設定中Microsoft.EntityFrameworkCore.Database.Command設定,並且在nlog.config必須一起設定。
{
  "ConnectionStrings": {
    "DefaultConnection": "server=資料庫IP;user id=資料庫帳號;password=資料庫密碼;database=資料庫名稱;TrustServerCertificate=true"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Trace",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.EntityFrameworkCore.Database.Command": "Information"
    }
  },
  "AllowedHosts": "*"
}

4.調整nlog.config檔案。

針對Microsoft.EntityFrameworkCore.Database.Command設定
<?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"
internalLogLevel="Error">
...
<!-- 設定 logger 名稱與 log 儲存目標的對應 -->
<rules>
<!--寫入SQL-->
<logger name="Microsoft.EntityFrameworkCore.Database.Command" minlevel="Info" writeTo="allfile" />
...
</rules>
</nlog>

5.修改Program.cs

增加EFCore設定。
public class Program
{
	public static void Main(string[] args)
	{
		var builder = WebApplication.CreateBuilder(args);
		
		//註冊EFCoreContext
		//先注入EFCore再注入Nlog才會記錄SQL命令
		string connectString = builder.Configuration.GetConnectionString("DefaultConnection");
		builder.Services.AddDbContext<MyDbContext>(options => options.UseSqlServer(connectString));

		//將NLog註冊到此專案內
		builder.Logging.ClearProviders();
		builder.Host.UseNLog();

		...
		var app = builder.Build();
		
		...
		app.Run();
	}
}

6.修改範本Controller程式碼

private readonly ILogger<WeatherForecastController> _logger;
private readonly MyDbContext _dbContext;

public WeatherForecastController(MyDbContext dbContext,ILogger<WeatherForecastController> logger)
{
	_dbContext = dbContext;
	_logger = logger;
}

public IEnumerable<WeatherForecast> Get()
{
IEnumerable<WeatherForecast> temp = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToList();

IEnumerable<TestUser> temp2 = _dbContext.User.ToList();

_logger.LogDebug("WeatherForecast List = {@temp}", temp);
_logger.LogDebug("TestUser List = {@temp}", temp2);
return temp;
}

7.確認Log內容與資料庫比對

Log內容:
資料庫內容:

由此可以確認資料庫中的內容與Log TestUser是一致的。
此外,如果Log內容不正確,可以將專案清除再重建,可能是什麼被cache造成的。