講故事
前幾天看公司一個新項目使用了FluentValidation,大家都知道FluentValidation是一個非常強大的用于構建強類型驗證規則的 .NET 框架,幫程序員解決了繁瑣的校驗問題,用起來非常爽,但我還是遇到了一件非常不爽的事情,如下代碼所示:
public?class?UserInformationValidator?:?AbstractValidator<UserInformation>{public?UserInformationValidator(){RuleFor(o?=>?o.UserName).Length(2,?20).WithMessage("姓名長度輸入錯誤");RuleFor(o?=>?o.Sex).Must(o=>o=="男"||o=="女").WithMessage("性別輸入錯誤");RuleFor(o?=>?o.Age).ExclusiveBetween(0,?200).WithMessage("年齡輸入錯誤");RuleFor(o?=>?o.Email).EmailAddress().WithMessage("郵箱輸入錯誤");}}static?void?Main(string[]?args){UserInformation?userInformation?=?new?UserInformation();userInformation.UserName?=?"";userInformation.Sex?=?"女";userInformation.Age?=?2200;userInformation.Email?=?"xxxxx";UserInformationValidator?validationRules?=?new?UserInformationValidator();var?result=???validationRules.Validate(userInformation);if?(!result.IsValid){Console.WriteLine(?string.Join(Environment.NewLine,?result.Errors.Select(x?=>?x.ErrorMessage).ToArray()));}}
我們每驗證一個對象,就要新建一個類型的驗證器 ,如上的UserInformationValidator ,雖然這樣寫邏輯上沒有任何問題,但我有潔癖哈,接下來我們試著封裝一下,嘿嘿,用更少的代碼做更多的事情。
安裝
在創建任何驗證器之前,您需要在項目中添加對 FluentValidation.dll 的引用。最簡單的方法是使用 NuGet 包管理器或 dotnet CLI。
模板化代碼封裝探索
將模板化的代碼提取到父類中
仔細看上面的代碼你會發現,我們每新建一個驗證器,就必須要創建一個繼承自AbstractValidator的類,其中T是您希望驗證的類的類型,封裝一個驗證器父類
public?class?CommonVaildator<T>?:?AbstractValidator<T>
{}
增加驗證規則
真正的業務邏輯是寫在UserInformationValidator驗證器里面的,而這塊代碼中只需要拿到RuleFor即可,其它的統一封裝到父類中,對不對,我們按照這個思路代碼,封裝一個長度驗證器規則。首先讓我們看看RuleFor的原型
public?IRuleBuilderInitial<T,?TProperty>?RuleFor<TProperty>(Expression<Func<T,?TProperty>>?expression)
它的參數是一個Func委托,那么Expression是什么呢?Experssion是一種表達式樹!
表達式樹是一種允許將lambda表達式表示為樹狀數據結構而不是可執行邏輯的代碼。
在C#中是Expression來定義的,它是一種語法樹,或者說是一種數據結構。其主要用于存儲需要計算、運算的一種結構,它只提供存儲功能,不進行運算。通常Expression是配合Lambda一起使用,這里就不做過多的解釋了!那么我們就能很輕易的封裝出長度驗證器規則了!
public?void?LengthVaildator(Expression<Func<T,?string>>?expression,?int?min,?int?max,?string?Message){RuleFor(expression).Length(min,?max).WithMessage(Message);}
同理,我們也可以接著封裝謂詞驗證器規則?郵箱驗證器規則等等
public?void?MustVaildator(Expression<Func<T,?string>>?expression?,Func<T,string,?bool>?expression2,?string?Message){RuleFor(expression).Must(expression2).WithMessage(Message);}public?void?EmailAddressVaildator(Expression<Func<T,?string>>?expression,?string?Message){RuleFor(expression).EmailAddress().WithMessage(Message);}
封裝驗證方法
上面我們把驗證器封裝好了,那么將 ?var result= ? validationRules.Validate(userInformation);這種驗證方法封裝一下不是手到擒來,代碼如下
public?static?string?ModelValidator<T>(T?source,?AbstractValidator<T>?sourceValidator)?where?T?:?class{var?results?=?sourceValidator.Validate(source);if?(!results.IsValid)return?string.Join(Environment.NewLine,?results.Errors.Select(x?=>?x.ErrorMessage).ToArray());elsereturn?"";}
測試封裝后的代碼
CommonVaildator<UserInformation>?commonUserInformation?=?new?CommonVaildator<UserInformation>();commonUserInformation.LengthVaildator(o?=>?o.UserName,?2,?30,?"姓名長度輸入錯誤");commonUserInformation.MustVaildator(o?=>?o.Sex,?(user,?_)?=>?user.Sex?=="男"||user.Sex=="女"?,?"性別輸入錯誤");commonUserInformation.ExclusiveBetweenVaildator(o=>o.Age,0,?200,?"年齡輸入錯誤");commonUserInformation.EmailAddressVaildator(o?=>?o.Email,?"郵箱輸入錯誤");string?msg=?VaildatorHelper.ModelValidator(userInformation,?commonUserInformation);Console.WriteLine(msg);
這樣代碼看起來是不是就簡潔多了,我這里就只封裝了四種驗證規則,其它的我就不在此封裝了。
總結
文章來源于工作中的點點滴滴,這也是我的即興封裝,大家要是有更好的封裝代碼,歡迎交流,獨樂樂不如眾樂樂,本篇就說到這里啦,希望對您有幫助。