.Net高級進階,教你如何構建企業模型數據攔截層,動態控制欄位驗證

来源:http://www.cnblogs.com/1996V/archive/2017/08/24/7423834.html
-Advertisement-
Play Games

現在,你有一個MVC架構的web項目,你要完成一個註冊功能。 前臺傳了3個值到你的控制器,分別是賬號、密碼、郵箱。 如圖:現在你要在控制器裡面判斷,賬號名稱、密碼、郵箱不能為空,並且名稱和密碼不超過16位。 上面這個圖只是個理想中的小例子,實際開發情況是,可能一次性要傳十幾個欄位甚至更多。 那麼在實 ...


現在,你有一個MVC架構的web項目,你要完成一個註冊功能。

前臺傳了3個值到你的控制器,分別是賬號、密碼、郵箱。

如圖:現在你要在控制器裡面判斷,賬號名稱、密碼、郵箱不能為空,並且名稱和密碼不超過16位。

上面這個圖只是個理想中的小例子,實際開發情況是,可能一次性要傳十幾個欄位甚至更多。

那麼在實際開發中,通常為了復用性,我們將這3個參數用一個實體類來代替。

即如下所示。

註:這一步會有個知識點,叫做模型驗證,不懂的童鞋可以百度下,MVC會通過一定規則自動直接將參數反序列化成所對應的實體類,但是因為我這個示例是webapi模式的,寫法略有不同,所以還要在參數前加個[FromBody]才能自動反序列化。

至於具體為什麼會自動反序列化,在本篇並不是我要講的主題,所以感興趣的童鞋可以百度下:MVC下的ModelBinder    。

攔截層的解耦

現在,我認為把實體類驗證給帶到控制器里去寫的這種方式有點不美,如果業務規則多的話,那麼這樣的驗證代碼就非常龐大,並且如果整個項目都採用這種驗證模式,那麼在我日後的維護階段中就顯得有點臃腫的感覺,實體類依賴於控制器方法去驗證,我得先找到這個實體類,然後仔細想想有哪些方法用到了該實體類,又做了哪些驗證判斷,然後維護。

那麼我能不能在控制器方法中 驗證實體類這一步 給挪掉,不寫到控制器的方法當中,寫在另一個地方,統一進行管理,實現實體類的驗證與控制器中的方法業務邏輯分除。

這種行為操作有點像httpModule,思想上就是設計模式所謂的降低耦合性了。

那麼怎麼做呢?

我們可以直接在實體類中加驗證,如圖

上面看到[Required],[StringLength],[RegularExpression]的這些叫做驗證特性,是.net框架已經封裝好的,它會對標註特性的欄位採取驗證。

[Required]限制了必須輸入,[Required(ErrorMessage = "請輸入用戶名")]  

[StringLength]限制了規定的長度,[StringLength(10, ErrorMessage = "長度不能超過10個字元")]  

[Range] 限制了值的範圍,[Range(0, 120, ErrorMessage = "年齡範圍在0到120歲之間")]  

[RegularExpression] 限制了必須滿足正則表達式,[RegularExpression(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$", ErrorMessage = "請輸入Email格式")]  

[Compare]限制了與之對應的欄位相等,[Compare("pwd", ErrorMessage = "兩次密碼要一致")]  //該特性標註的欄位值必須與pwd欄位值相等

.net也就封裝了幾個,這5個用的最多(當然,也可以自定義這種驗證特性,對這塊想深入瞭解的請百度:mvc ValidationAttribute)。

那麼我標註了特性後如何進行判斷呢?

  

我們看下控制器方法中的寫法:

如圖,用 ModelState.IsValid  這段話來對驗證結果進行判定,如果實體類上的被標註的特性滿足條件的話,就為true,否則為false。

那麼,因為這種模型驗證是種模式,是全局的,所以應該單獨拿出來在攔截層進行註冊。

如圖:

這段代碼的意思就是:每當進入控制器方法之前,會判斷這個方法的名稱,如果包含的有Insert、check、update這三者的任意一個,都會進行攔截驗證(對模型驗證的結果進行判定),如果為false,那麼就返回給客戶端一個400狀態碼。

然後註冊一下:(註冊的地方只是個範例,因為我是webapi,只對http進行攔截)

 

model負責填寫規則,驗證由專門的驗證人員去做,邏輯由專門的邏輯人員去寫,這樣就各司其職了。

 不過,這才只是第一步!

(隨著你日常的開發,你肯定會遇到這種情況)

user實體類,是專註於註冊方法,說白了,就是為註冊方法所寫的,

我現在還要寫個登錄方法。

但是登錄的時候,我不需要填寫email,只需要填寫賬號和密碼,對這兩個欄位進行驗證。

可是我的實體類裡面對email做了[Required]和[RegularExpression]驗證,那麼這樣就導致了 如果我登錄方法繼續使用這個user實體類,那麼肯定會報錯,會返回個400驗證碼。

這種情況我該怎麼解決?難道重新建個model?再重新給一遍規則?這還僅僅只有3個欄位,萬一有的表中有十幾個欄位,二十幾個欄位甚至更多怎麼辦?

重新建個model肯定不行,這樣已經失去了   復用性、各司其職  的初衷。

求解決方案!線上等!

...

模型驗證進階:自由控制需要驗證的欄位

百度了一下,網上沒有該方面的教程,博客園中也沒找到,群里也沒交流出個結果,但這種情況卻經常遇到!

 梳理下思路,大致有幾種,第一種是用某種手段控制類中的這些驗證特性,或者控制類中的屬性欄位,如啟用或停用,但是c#不能對屬性欄位進行停啟用,而控制類中的這些驗證特性也有點天方夜譚,本身就是微軟封裝好的,你得反編譯一下看下源碼,然後重構?或者你直接不用這些框架封裝好的驗證特性,使用自己定義自定義驗證特性,然後把控制方法都寫在裡面?這樣太麻煩,而且違背初衷。自定義ModelBinder ?更扯淡。

一番折騰無果,那麼就不能從特性本身找突破口了,這時,我把目標轉移到ModelState.IsValid上,換一種思路實現。

我們發現其實現了GetEnumerator方法,於是對其進行遍歷,可以獲取到特性所綁定的欄位屬性的名稱以及其狀態。

因為要實現自由控制需要驗證的欄位,所以無論怎樣實現,都只能通過 自定義特性 標註在方法體頭上來實現。

而理想的最終呈現效果應該是這樣的:

放圖:

 

或者

 

 

使用方式:

如果方法頭上有KeepZ特性的話,就進入自由控制驗證欄位狀態。

 

[KeepZ("欄位1","欄位2")]  即:只對  欄位1 和 欄位2   進行驗證

[KeepZ(false,"欄位3")]  即:除了  欄位3  之外,其餘欄位都進行驗證

 

 

那麼我們放下具體實現代碼:

 

 public override void OnActionExecuting(HttpActionContext actionContext)
        {
            if ((actionContext.ActionDescriptor.ActionName.ToUpper().Contains("INSERT") || actionContext.ActionDescriptor.ActionName.ToUpper().Contains("CHECK") ||
                 actionContext.ActionDescriptor.ActionName.ToUpper().Contains("UPDATE")))
            {
                var ia = actionContext.ActionDescriptor.GetCustomAttributes<KeepZ>();
                if (ia.Count != 1)
                {
                    goto result;
                }
                foreach (KeyValuePair<string, ModelState> item in actionContext.ModelState.ToArray())
                {
                    if (ia[0].Modes == false)
                    {
                        foreach (string PropertysValue in ia[0].Propertys)
                        {
                            if (item.Key.Contains(PropertysValue))
                            {
                                actionContext.ModelState.Remove(item.Key);
                            }
                        }
                    }
                    else
                    {
                        bool re = false;
                        foreach (string PropertysValue in ia[0].Propertys)
                        {
                            if (item.Key.Contains(PropertysValue))
                            {
                                re = true;
                            }
                        }
                        if (re == false)
                        {
                            actionContext.ModelState.Remove(item.Key);
                        }
                    }
                }
                result: if (!actionContext.ModelState.IsValid)
                {
                  
                    actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
                   
                      
                }
            }
        }
/// <summary>
    ///  保持
    /// </summary>
    public class KeepZ : Attribute
    {
        public string[] Propertys = null;
        public bool Modes = true;
        public KeepZ(params string[] Property)
        {
            Propertys = Property;
        }
        public KeepZ(bool Mode, params string[] Property)
        {
            Propertys = Property;
            Modes = Mode;
        }
    }

如此一來,就需要再重建Model這樣低端的方法了,現在MVC架構大多都用這種驗證模式,但是卻沒有  自由選擇驗證欄位的解決方案,每每遇到該情況,只能無奈重新建個實體類,對比之下,根本沒有食得這種攔截層模型驗證的精髓,只學個模子,反而弄巧成拙不成本意,所以我寫了此篇和大家一起分享,加入了KeepZ來控制需要驗證的欄位,就是真正的實現了  可 復用  ,邏輯與攔截分層  了。

Demo雖小,但是這種情況下的解決方案,我在博客園中沒找到,應該是園子里第一篇吧。

 

作者:小曾
出處:http://www.cnblogs.com/1996V/p/7423834.html 歡迎轉載,但任何轉載必須保留完整文章,在顯要地方顯示署名以及原文鏈接。如您有任何疑問或者授權方面的協商,請給我留言

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1創建文件repo文件 #vim /etc/yum.repos.d/mongodb-org-3.4.repo [mongodb-org-3.4] name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/redhat/$releasev ...
  • 三層架構 常見架構: 開發中常見的23種設計模式: 創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。 結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。 行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、 ...
  • 1 private string GetMD5(string sDataIn) 2 { 3 MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider(); 4 byte[] bytValue, bytHash; 5 byt... ...
  • ServiceHub.DataWarehouseHost.exe記憶體泄漏問題的處理。 ...
  • 1 using System; 2 using System.Reflection; 3 4 namespace DynamicCall 5 { 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 Console.WriteLin... ...
  • 前不久,在工作中由於預設(xihuan)使用Async、Await關鍵字受到了很多質問,所以由此引發這篇博文“為什麼我們要用Async/Await關鍵字”,請聽下麵分解: Async/Await關鍵字 Visual Studio(.net framework 4.5)提供了非同步編程模型,相比之前實現 ...
  • IO操作的MDA(Direct memory access)模式:直接訪問記憶體,是一種不經過CPU而直接進行記憶體數據存儲的數據交換模式,幾乎可以不損耗CPU的資源; CLR所提供的非同步編程模型就是充分利用硬體的DMA功能來釋放CPU的壓力;使用線程池進行管理,非同步將工作移交給線程池中的某個工作線程來 ...
  • Control.Dispatcher.BeginInvoke里的邏輯由UI線程執行,如果內部包含耗時操作就會造成界面卡住。 Action.BeginInvoke里的邏輯,將在一個新開的線程中執行,而不是UI線程,所以不會造成界面卡住。但其內部不能直接對UI操作,所以若需要訪問UI,需要將訪問UI的那 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...