ShowProgramCode

2023年9月26日 星期二

golang 的 automapper

在C#有automapper套件,可以將兩個相似的資料結構Mapping內容。
光是這個鏡射寫入屬性值的功能,讓我可以不用每次遇到類似的物件都要一個個屬性賦值,就已經非常好用了。
最近必須要些golang時,也遇到了類似的問題,目前找到一個還可以用的套件,特別記錄下來。
(其實是因為上次程式碼即便上了git也一下子找不到...哭...)

import (
"github.com/mitchellh/mapstructure"
)

type User struck{
Id int
Name string
Phone string
....
}

type Member struck{
Name string
Phone string
...
}

//從資料庫讀取使用者後,將資料放入Member
var member Member{}
user := db.load(id)
err = mapstructure.Decode(user, &member)

這樣就可以將相同屬性名稱的值寫入member。
假使兩個欄位名稱有出入該怎麼辦??
目前還沒有測試到那裡,也許這個套件也有提供類似的功能,今天簡單記錄到此。

2023年7月4日 星期二

C# Net6 XML轉物件 錯誤訊息 ... xmlns='' was not expected

今天遇到需要將DTO與XML相互轉換,但卻一直遇到狀況。
後續處理完畢,特別紀錄一下。

XML:

<massege>
<header code="OTP" id="PUSID">
<from>127.0.0.1</from>
<to>255.0.0.0</to>
</header>
<body>
訊息內容
</body>
</message>

DTO:

[XmlTypeAttribute(AnonymousType = true)]
[XmlRootAttribute(Namespace = "", IsNullable = false, ElementName = "message")]
public class TestMessage
{
	public TestMessageHeader header{get;set;}
	public string body{get;set;}
}

[XmlTypeAttribute(AnonymousType = true)]
public class TestMessageHeader
{
	[XmlAttributeAttribute()]
	public string code { get; set; } = string.Empty;
	[XmlAttributeAttribute()]
	public string id { get; set; } = string.Empty;
	public string from {get;set;} = string.Empty;
	public string to{get;set;} = string.Empty;
}

程式碼:

public static string XmlToDto<T>(string xml, ref T obj) where T : class
{
	XmlSerializer Serializer = new XmlSerializer(typeof(T));
	try
	{
		using (StringReader reader = new StringReader(xml))
		{
			obj = (T)Serializer.Deserialize(reader);
		}

		return "0000";
	}
	catch (Exception ex)
	{
		return ex.Message;
	}
}

public static string XmlToDto<T>(string xml, string rootTag, ref T obj) where T : class
{
	XmlSerializer Serializer = new XmlSerializer(typeof(T), new XmlRootAttribute(rootTag));
	try
	{
		using (StringReader reader = new StringReader(xml))
		{
			obj = (T)Serializer.Deserialize(reader);
		}

		return "0000";
	}
	catch (Exception ex)
	{
		return ex.Message;
	}
}

參考網頁:https://dotblogs.com.tw/initials/2020/11/18/184450

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造成的。