ShowProgramCode

2023年9月26日 星期二

golang 的 automapper

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

  1. import (
  2. "github.com/mitchellh/mapstructure"
  3. )
  4.  
  5. type User struck{
  6. Id int
  7. Name string
  8. Phone string
  9. ....
  10. }
  11.  
  12. type Member struck{
  13. Name string
  14. Phone string
  15. ...
  16. }
  17.  
  18. //從資料庫讀取使用者後,將資料放入Member
  19. var member Member{}
  20. user := db.load(id)
  21. err = mapstructure.Decode(user, &member)

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

2023年7月4日 星期二

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

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

XML:

  1. <massege>
  2. <header code="OTP" id="PUSID">
  3. <from>127.0.0.1</from>
  4. <to>255.0.0.0</to>
  5. </header>
  6. <body>
  7. 訊息內容
  8. </body>
  9. </message>

DTO:

  1. [XmlTypeAttribute(AnonymousType = true)]
  2. [XmlRootAttribute(Namespace = "", IsNullable = false, ElementName = "message")]
  3. public class TestMessage
  4. {
  5. public TestMessageHeader header{get;set;}
  6. public string body{get;set;}
  7. }
  8.  
  9. [XmlTypeAttribute(AnonymousType = true)]
  10. public class TestMessageHeader
  11. {
  12. [XmlAttributeAttribute()]
  13. public string code { get; set; } = string.Empty;
  14. [XmlAttributeAttribute()]
  15. public string id { get; set; } = string.Empty;
  16. public string from {get;set;} = string.Empty;
  17. public string to{get;set;} = string.Empty;
  18. }

程式碼:

  1. public static string XmlToDto<T>(string xml, ref T obj) where T : class
  2. {
  3. XmlSerializer Serializer = new XmlSerializer(typeof(T));
  4. try
  5. {
  6. using (StringReader reader = new StringReader(xml))
  7. {
  8. obj = (T)Serializer.Deserialize(reader);
  9. }
  10.  
  11. return "0000";
  12. }
  13. catch (Exception ex)
  14. {
  15. return ex.Message;
  16. }
  17. }
  18.  
  19. public static string XmlToDto<T>(string xml, string rootTag, ref T obj) where T : class
  20. {
  21. XmlSerializer Serializer = new XmlSerializer(typeof(T), new XmlRootAttribute(rootTag));
  22. try
  23. {
  24. using (StringReader reader = new StringReader(xml))
  25. {
  26. obj = (T)Serializer.Deserialize(reader);
  27. }
  28.  
  29. return "0000";
  30. }
  31. catch (Exception ex)
  32. {
  33. return ex.Message;
  34. }
  35. }

參考網頁: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檔案。

記得必須選擇"永遠複製"到輸出目標。
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. autoReload="true"
  5. internalLogLevel="Error">
  6. <!-- 啟用 ASP.NET Core layout renderers -->
  7. <extensions>
  8. <add assembly="NLog.Web.AspNetCore"/>
  9. </extensions>
  10. <!-- 設定log根目錄 -->
  11. <variable name="logDirectory" value="C:\TWBank_Log\NlogTest" />
  12. <!-- log 儲存目標 -->
  13. <targets>
  14. <target xsi:type="File" name="allfile" fileName="${logDirectory}\nlog-all-${shortdate}.log"
  15. layout="${date:format=HH\:mm\:ss\.ffff} [thread:${threadid}] ${level:uppercase=true} ${message} ${exception:Format=ToString}" createDirs="true" encoding="UTF-8" />
  16. </targets>
  17. <!-- 設定 logger 名稱與 log 儲存目標的對應 -->
  18. <rules>
  19. <!--將Microsoft與System.Net.Http的錯誤拿掉不紀錄-->
  20. <logger name="Microsoft.*" maxlevel="Info" final="true" />
  21. <logger name="System.Net.Http.*" maxlevel="Info" final="true" />
  22. <logger name="*" minlevel="Trace" writeTo="allfile" />
  23. </rules>
  24. </nlog>

3.修改Program.cs

  1. public class Program
  2. {
  3. public static void Main(string[] args)
  4. {
  5. var builder = WebApplication.CreateBuilder(args);
  6.  
  7. //將NLog註冊到此專案內
  8. builder.Logging.ClearProviders();
  9. builder.Host.UseNLog();
  10.  
  11. ...
  12. var app = builder.Build();
  13. ...
  14. app.Run();
  15. }
  16. }

4.調整appsettings.json

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

5.修改範本Controller程式碼

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

6.確認Log內容

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

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

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Sqlite

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

  1. public class MyDbContext: DbContext
  2. {
  3. public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
  4. {
  5. }
  6. public DbSet<TestUser> User { get; set; }
  7. }
  8.  
  9. [Table("TestUser")]
  10. public class TestUser
  11. {
  12. [Key]
  13. public int Id { get; set; }
  14. [Required]
  15. [StringLength(20)]
  16. public string Name { get; set; } = string.Empty;
  17. [Required]
  18. [StringLength(15)]
  19. public string Phone { get; set; } = string.Empty;
  20. }

3.修改appsettings.json

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

4.調整nlog.config檔案。

針對Microsoft.EntityFrameworkCore.Database.Command設定
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. autoReload="true"
  5. internalLogLevel="Error">
  6. ...
  7. <!-- 設定 logger 名稱與 log 儲存目標的對應 -->
  8. <rules>
  9. <!--寫入SQL-->
  10. <logger name="Microsoft.EntityFrameworkCore.Database.Command" minlevel="Info" writeTo="allfile" />
  11. ...
  12. </rules>
  13. </nlog>

5.修改Program.cs

增加EFCore設定。
  1. public class Program
  2. {
  3. public static void Main(string[] args)
  4. {
  5. var builder = WebApplication.CreateBuilder(args);
  6. //註冊EFCoreContext
  7. //先注入EFCore再注入Nlog才會記錄SQL命令
  8. string connectString = builder.Configuration.GetConnectionString("DefaultConnection");
  9. builder.Services.AddDbContext<MyDbContext>(options => options.UseSqlServer(connectString));
  10.  
  11. //將NLog註冊到此專案內
  12. builder.Logging.ClearProviders();
  13. builder.Host.UseNLog();
  14.  
  15. ...
  16. var app = builder.Build();
  17. ...
  18. app.Run();
  19. }
  20. }
  21.  

6.修改範本Controller程式碼

  1. private readonly ILogger<WeatherForecastController> _logger;
  2. private readonly MyDbContext _dbContext;
  3.  
  4. public WeatherForecastController(MyDbContext dbContext,ILogger<WeatherForecastController> logger)
  5. {
  6. _dbContext = dbContext;
  7. _logger = logger;
  8. }
  9.  
  10. public IEnumerable<WeatherForecast> Get()
  11. {
  12. IEnumerable<WeatherForecast> temp = Enumerable.Range(1, 5).Select(index => new WeatherForecast
  13. {
  14. Date = DateTime.Now.AddDays(index),
  15. TemperatureC = Random.Shared.Next(-20, 55),
  16. Summary = Summaries[Random.Shared.Next(Summaries.Length)]
  17. })
  18. .ToList();
  19.  
  20. IEnumerable<TestUser> temp2 = _dbContext.User.ToList();
  21.  
  22. _logger.LogDebug("WeatherForecast List = {@temp}", temp);
  23. _logger.LogDebug("TestUser List = {@temp}", temp2);
  24. return temp;
  25. }

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

Log內容:
資料庫內容:

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