包含標籤 CSharp 的文章

使用 AddTypeMap 調整型別映射,讓 Dapper 乖乖寫入 0001-01-01 到 datetime2

Image

這週忙著打黑悟空,簡單記一下前陣子同事遇到的一個場景:

由於曆法的關係,SQL Server 的 datetime 範圍只能從 1753-01-01 開始。
如果我們要寫入 0001-01-01 進去的話就會報錯

SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.

補充:關於曆法的部份,有興趣的朋友可以參考這篇:
淺談:消失的日期,以關聯式資料庫的日期資料類型為例 - 德瑞克:SQL Server 學習筆記

這時候通常去把資料表欄位改成香香的 datetime2 就可以搞定,爽爽寫入 0001-01-01。

但如果我們正在使用 Dapper,預設會把 C# 的 DateTime 映射到 SQL Server 的 datetime,所以還是會寫入失敗。

這時候我們就需要明確地請 Dapper 幫我們使用 datetime2 來進行處理。


如果傳遞的只是某個參數,使用 DbType 就行了:

var parameters = new DynamicParameters();
parameters.Add("@Birthday", birthday, DbType.DateTime2);

但如果傳遞的是某個 Model 裡的特定欄位呢?例如:

public class HistoricalEvent
{
    public Guid EventId { get; set; }       // 歷史事件的唯一識別碼
    public string Description { get; set; } // 歷史事件的描述
    public DateTime EventDate { get; set; } // 歷史事件發生的日期, 可能早於 1753 年!
}

這種時候就可以使用 AddTypeMap 來調整一下 Dapper 的映射型別。

……

閱讀全文


.Net: 使用 FeatureManagement 套件來實作功能切換(Feature Toggle)吧

Image

在做上一篇 IOptions 的筆記時,剛好看到 FeatureManagement 這香東西。
馬上來收錄一篇。順便也簡單整理一下 Feature Flag (≒Feature Toggle) 的介紹。

認識一下 Feature Flag

本部落格秉持著「簡單、友善、我好菜」的精神,按照慣例先簡單介紹一下
已經知道的朋友就可以跳過這個小節,直接前往 #環境準備 囉。

假設我們原本有 Old 邏輯:

Old();

天庭傳來諭令,要我們改成 New 邏輯。這簡單,我們就把 Old 砍掉,換成 New。非常自然,改完就佈版

New();

隔天,天庭又傳來諭令,New 需要調整一下,先不要了
現在我們又需要把 New 邏輯砍掉,讓 Old 邏輯回來。
簡單,但看來我們得再上一版

Old();
// New();

再隔天,大家可能猜到天庭又要幹嘛了,總之又上了一版

// Old();
New();

如此往復三萬八千次,工程師終於受不了了:「俺老孫每天在這切換 Old 跟 New,改完還得佈版,每天搞這些就飽了,我滴媽呀,不幹了」

就在老孫關燈走人的那一瞬間,突然靈光一現:等等,俺加個開關還不行嗎?

……

閱讀全文


.Net: 使用 IOptions 取得 appsettings.json 的設定值吧

Image

因為手邊的 .Net Core API 專案越來越多,蠻常會需要讀 appsetting.json 的 Config,每次都要重找文章有點麻煩,這邊就來筆記一篇。

認識 Appsettings.json

首先簡單介紹一下 appsettings.json 是在幹嘛的:

我們開發的時候,常常會需要先設定好一些服務參數、組態設定之類的設定值,再用這些設定值用來控制我們程式的某些行為。例如:

  • 「某功能的上限值是 10
  • 「某項開關在測試環境是 false
  • 「某服務信件的發送者要用 noreply9527

另外常見的還有連線字串、寫 Log 時的 logging level 等等。

這些設定值會和程式碼拆開,放在設定檔集中管理,再讓程式碼從設定檔讀取相關的設定值來用就好,藉此來把設定值的管理和使用做個關注點分離。

有了設定檔,要調整修改也比較方便:要增加或是修改設定值,都只要先往設定檔衝就行。並且因為兩邊拆開了,我們也就可以簡單地替換這些設定值來應對不同狀況(例如正式環境和測試環境套用兩組不同的設定檔,或是在自己電腦測試的時候快速改個值之類的),彈性可說是 UPUP!

更重要的是,這樣我們就不需要把一大堆東西寫死在程式碼的各個地方,也就不會要改個值還要先搜尋整個專案再一個一個挖出來改了。我按 Shift Ctrl F 已經按到哭

把設定值抽出去丟到設定檔之後,我們就得到了:集中管理設定值、方便修改和替換、減少程式碼中又重複又寫死的臭東西等等好處。

在 .Net Core 的世界裡,這個設定檔就是 appsettings.json
前面提到的像是日誌等級、功能旗標之類的這些設定值,就會放在 appsettings.json 裡面。

而當我們想要從 appsettings.json 把這些設定值給讀出來的時候,
就可以使用我們的 IOptions 啦!

使用 IOptions 來註冊 & 注入

提醒:這篇的示範會用到一些些 .Net 依賴注入(DI)相關的操作。沒接觸過的朋友可以考慮先閱讀菜雞新訓記:依賴注入

假設我們有個專案,叫做大漢防禦管理系統。專案內的 appsettings.json 有以下內容:

{
  "StrongholdInfo": {
    "Index": 49,
    "Name": "劍閣",
    "Enabled": true, 
    "General": [
      "姜維",
      "廖化",
      "張翼",
      "董厥"
    ]
  }
}

我們正好在開發一個新功能,需要抓到這段設定值。現在就來示範一下:

……

閱讀全文


使用 .Net 的 System.Drawing 產生簡單的文字 Banner 初體驗

Image

原本我都是用產生 FB 封面的「康熙字典體產生器」來做簡單的文字 Banner,就拿來當作文章的封面照

用了好一陣子也沒啥問題。結果某天文章寫好,吃著火鍋唱著歌,產生器打開一看,服務竟然就沒了!

當下是一個震驚啊,一氣之下決定直接打開 Linqpad 寫一個。

註:現在搜尋康熙字典體產生器,還查得到介面截圖,還真的蠻簡單方便的 Q_Q

以前面的菜雞與物件導向系列 Banner 為例,我們大概需要:

  • 產生一張圖
  • 在圖上面放主標題和副標題
  • 關鍵字可以上色

Image

稍微搜尋一下發現 .Net 已經有 System.Drawing 這個工具可以幫我們完成這些簡單的圖片任務,事不宜遲馬上就來嘗試!

……

閱讀全文


Polyglot Notebooks -- 在 VSCode 簡單迅速地撰寫 C# 腳本吧

Image

像我這樣的菜鳥工程師,在 Coding 的時候時常會需要簡單試一些想法。像是「我這邊下了這串 Linq 出來的資料,到底是不是我想要的內容啊 = =?」

或是在進行開發任務時:「這個步驟能不能這樣做啊?先拆個簡單的 Method 試試看好了」之類的

以往遇到這種時候,我都會打開香香的 Linqpad 直接無情開寫,快速地作個小小的概念驗證。

畢竟 Linqpad 可以迅速地開始撰寫簡單的 C# 腳本,並且有良好的語法提示、Nuget 支援和方便的資料庫連線,省去我還要開一個 Console 專案自己弄這些東西,更可以存著之後備查,所以一直以來我都愛不釋手。

但在因緣際會下(其實就是閒逛論壇的時候),發現了微軟把拔出的 Polyglot Notebooks 這款 VSCode 擴充套件。當下驚為天人!Linqpad 在我心中的地位就這麼動搖了

Polyglot Notebooks 可以讓我們直接在 VSCode 上面撰寫簡單的 C#、F#、JavaScirpt 等腳本、迅速驗證想法。甚至可以對程式碼分段、加入 Markdown 文檔,讓我們能更有邏輯、有步驟地撰寫我們的腳本、處理我們的資料。

它的特色是這麼對我的胃口,看來我以後鐵定是會用到的。現在就來簡單記錄 Polyglot Notebooks 的使用方式吧!

……

閱讀全文


菜雞新訓記 (7): 使用 Fluent Validation 來驗證參數吧

Image

這是俺整理公司新訓內容的第七篇文章,目標是紀錄 Fluent Validation 這個好用套件。

FluentValidation 可以幫我們將 Api 傳入的參數的檢查用更口語、更乾淨的方式去處理,除了可以將檢查邏輯拆分成單獨的 Validator 類別,更提供了許多內建的檢查規則和自訂的彈性,相當方便。

並且因為將參數的檢查邏輯整理出去,就可以和 Controller 本身的工作做簡單的拆分,達到關注點分離的目標。

現在就讓我們來認識一下這個好用工具吧!首先要從很久很久以前開始說起…

前言

西元前的某一天,憂心的皇帝在朝堂內繞著柱子走,突然大臣奪門而入。

大臣:「陛下!敵軍已經攻到國境內啦!」

皇帝大驚:『邊境的那些檢查站和關口難道都陷落了嗎?不可能!』

大臣:「陛下,有內奸和敵國勾結,檢查站完全沒檢查!髒資料已經闖進來了!」

皇帝喊了一聲:『怎麼可能!讓朕看看!』就打開 Controller 和前一個版本的 Git Log,這一看差點就昏了過去。

原來 Controller 的舊程式碼就已經很亂了,檢查參數的條件 if/else 和其他呼叫的方法、組裝資料都雜在一起。結果這次專案改動時,某一行就被內奸改壞了,關鍵的參數竟然沒檢查到!

『可,可惡!來人啊,把工程師推出午門斬首!』

「皇上!他已經離職啦!」

皇帝跌坐在地,懊悔地說:『如果當初有好好把檢查參數跟實際組資料的部份都拆開的話,也許就不會這樣了…』

「是啊,如果我們有用 Fluent Validation…!」

專案現況

大臣提到的 FluentValidation 是一套能幫我們把傳入參數的分離出去、用更口語化的方式去撰寫的工具。

……如果當時他們有使用 Fluent Validation 來把驗證的邏輯和規則跟原本很亂的 Controller 切分的話,說不定就能及時發現問題吧,大概。

為了不要步上他們的後塵,就讓我們直接回到本系列的卡牌管理 API 服務來加上這個好用工具吧!

……

閱讀全文


AutoMapper 使用 ConvertUsing 自定義類型轉換,將包含串列成員的物件映射為一組串列

從朋友那兒聽到了用 AutoMapper 把串列成員物件攤平成一組串列的問題,發現了 ConvertUsing 的好用,這邊就紀錄一下。

事情是這樣的,首先有一個 Parent 類別,其中包含著兩個成員:Id 和串列的 Child 類別,而 Child 類別則只有一個成員 Val,如下:

public class Parent
{
    public int Id { get; set; }
    public IEnumerable<Child> Children { get; set; }
}

public class Child
{
    public double Val { get; set; }
}

另外還有一個 Target 類別,包含 IdVal 兩個成員:

public class Target
{
    public int Id { get; set; }
    public double Val { get; set; }
}

現在的目標是:將一個有著 Child 串列的 Parent 映射成 Target 串列

也就是說,假設我們的來源是這樣子:

var boo = new Parent
{
    Id = 1,
    Children = new List<Child>
    {
        new Child { Val = 1 },
        new Child { Val = 2 },
    }
};

希望可以變成這樣子:

var expect = new List<Target>
{
    new Target { Id = 1, Val = 1 },
    new Target { Id = 1, Val = 2 },
};

我之前遇到的時候,會直覺地將 Child 直接 Map 到 Target,再對 Target 做個 Foreach 來補上 Parent 的 Id。

這次和朋友討論時,提到了另一個角度:雖然這樣的做法相當直覺快速,但其實並不能保證後續維護的人使用這組 Mappings 時,都知道這裡要補資料;況且此處的對應關係的確是 ParentList<Target>,並非 ChildTarget 而已,直覺上就怪怪的。若要解決這個問題,可能就要再包裝一層,把 Mapper 隔離出去做個轉換器之類的。

但想想又覺得 AutoMapper 不可能沒提供這個場景能使用的方法才對,最後餵狗發現 AutoMapper 確實有提供 ConvertUsing 來讓我們客製化轉換過程,這邊就紀錄一下。

……

閱讀全文


菜雞新訓記 (6): 使用 依賴注入 (Dependency Injection) 來解除強耦合吧

Image

這是俺整理公司新訓內容的第六篇文章,目標是紀錄什麼是依賴注入(Dependency Injection)。包含:

並用 .net Core 實際跑一次依賴注入藉由將控制權轉移給注入容器,解除分層與分層間、類別與類別間的依賴和耦合關係,達到以介面分離實作的目標

前言

西元前的某一天,憂心的皇帝在朝堂內繞著柱子走,正巧被路過的廷尉看見。

廷尉:「敢問陛下在煩惱什麼呢?」

皇帝:『朕這是在想封賞的事兒哪。前朝之所以覆滅,根本的原因就在於大肆封賞臣下,四處分封土地給他們做諸侯。

這些諸侯呢,肆意起用自己喜歡的人擔任要職、結黨營私,心情好就 new 將軍("我ㄉ朋友");
十天就封了十個將軍。這些人若犯了錯,要處理他們還得看諸侯面子;而諸侯一聲令下,這些人便群起造反。

並且,這些諸侯之間彼此喜歡直接往來,動不動就在自家裡下命令給 隔壁諸侯.借糧草(100),哪天就變成 隔壁諸侯.揪團造反()。彼此之間偷來暗去,實在難以掌握。

最後呢,一個逆賊起來造反,若要將他給辦了,附近諸侯就一起響應,每個都一齊報錯,Exception 成千上百,國家也就這樣滅了,想到這朕就頭痛得很,不知愛卿可有法子?』

廷尉想了一想,便說:「陛下,此事要點還是在於諸侯之間相互依賴、彼此耦合,致生禍端。

臣有一計,先收回諸侯的人事任命權,使其不可私自 new 自己人,所有人事異動,須由中央進行管理與派遣。這樣即使諸侯要造反,也不知道下面這群打工仔是不是自己人。大家各司其職,諸侯做好自己的行政作業,打工仔派到崗位就做好自己的工作,彼此不直接依賴,這樣出事的機率就少了。

其次,明令禁止諸侯私自往來,對諸侯們進行隔離,若是有公務上的需要,一律藉由中央提供的接口來溝通,彼此之間明訂契約,由中央進行隔離與調派,諸侯間就只需要按照協議好的合約下去合作,這樣勾結的機會也就少了,耦合也就降低了。陛下覺得如何?」

皇帝大喜:『如此甚好!治眾如治寡,在於分而治之。此計可有名字?』

「此乃--依賴注入之計!」

……

閱讀全文


在 Swagger UI 加上驗證按鈕,讓 Request Header 傳遞 Authorize Token

Image

在先前的 菜雞新訓記 (4): 使用 Swagger 來自動產生簡單好看可測試的 API 文件吧 中,我們介紹了在 .net Core 環境使用 Swashbuckle 套件來產生 Swagger 文檔,並且直接在 Swagger UI 中呼叫 API 來進行測試。

但很多時候,我們的 API 會需要先驗證才能使用,例如在 Header 傳遞 Token 來驗證身分等等。這時候 Swagger UI 就會整個廢掉,打了都會出錯,很不方便。

因此這篇文章就紀錄一下如何在 Swagger UI 上加入 Authorize Token 的傳遞,讓 Swagger UI 在需要身分驗證的環境也能直接呼叫使用。

……

閱讀全文


菜雞抓蟲: DateTime.ToString() 之我們不一樣 & CultureInfo 文化特性小筆記

Image

事發緣由

咱們內部套件中有個方法,會將各個參數組合為 QueryString 去打指定的 Api。就是這麼稀鬆平常的場景,神奇的事情就發生了。

同樣的套件、同樣的語法,在團隊中兩個人的電腦上安裝執行,卻是一個成功一個失敗。

原來該方法的參數中,包含一欄型別為 DateTime 的資料,並且會把該欄位的值拿來 ToString() 再做為參數傳遞給目標 Api。

而呼叫失敗的人就是在這個 DateTime.ToString() 的過程中產生了中文字,使得目標 Api 接到參數後,無法將中文字轉換回 DateTime 而發生了錯誤。

問題就浮現了:同一行 DateTime.ToString() 在不同電腦執行的結果竟然不一樣?!

為了讓我們更快了解狀況,現在就簡單地使用 Linqpad 進行測試:

void Main()
{
    DateTime.Now.ToString().Dump();
}

首先,在我的 Windows 時間設定中,完整時間的格式為 09:40:07 ,也就是 24 小時制。

現在讓我們先執行上面這段語法看看:

// 2021/10/04 21:00:00

接著讓我們變更時間格式看看。

以我的 Win10 為例,在 Windows 工具列,也就是畫面的右下角右鍵,選擇 調整日期時間 → 日期時間格式設定 → 變更資料格式,將時間格式變更為 上午 09:40:07

重新啟動 Linqpad 再執行如下:

// 2021/10/04 下午 09:00:00

可以看到 下午 兩個字就蹦出來了!

之所以會有這樣的差異,是因為 DateTime.ToString() 預設轉換的目標格式會是抓取目前執行緒的文化特性

……

閱讀全文


系列文

轉貼文

最近文章

分類

標籤

友鏈

統計資訊

工商服務

    DDDTaiwan