日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

客官,.NETCore无代码侵入的模型验证了解下

發(fā)布時間:2023/12/4 asp.net 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 客官,.NETCore无代码侵入的模型验证了解下 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

.NETCore下的模型驗證相信絕大部分的.NET開發(fā)者或多或少的都用過,微軟官方提供的模型驗證相關(guān)的類位于System.ComponentModel.DataAnnotations命令空間下,在使用的時候只需要給屬性添加不同的特性即可實現(xiàn)對應(yīng)的模型驗證。如下所示:

?

public class Movie {public int Id { get; set; }[Required][StringLength(100)]public string Title { get; set; } }

在WebApi中,當(dāng)請求接口時,程序會自動對模型進(jìn)行驗證,如無法驗證通過,則會直接終止后續(xù)的邏輯執(zhí)行,并響應(yīng)400狀態(tài)碼,響應(yīng)內(nèi)容如下所示:

{ "type": "https://tools.ietf.org/html/rfc7231#p-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "00-4b16460fc83d7b4daa4f10d939016982-f823eebede419a4a-00", "errors": { "aa": [ "The aa field is required." ] } }

當(dāng)然,你也可以自定義響應(yīng)的內(nèi)容,這不是本文的重點。本文的重點是,.NETCore系統(tǒng)默認(rèn)的模型驗證功能并不夠強(qiáng)大,僅支持在Controller的Action中使用,不支持非Controller中或者控制臺程序的驗證,且代碼侵入性較強(qiáng)。

而FluentValidation(https://fluentvalidation.net/?)則是功能更為強(qiáng)大的模型驗證框架,支持任何場景下的模型驗證,且不侵入代碼。

下面就來和筆者一起了解下FluentValidation的用法。

?

接入

FluentValidation支持一下平臺:

  • .NET 4.6.1+

  • .NET Core 2.0+

  • .NET Standard 2.0+

各個平臺的集成方式大同小異,本文僅講解.NETCore3.1的集成方式。

首先,使用NuGet安裝FluentValidation.AspNetCore依賴。

添加需要驗證的模型類,如Student類,代碼如下:

public class Student {public int Id { get; set; }public int Age { get; set; }public string Name { get; set; } }

然后創(chuàng)建類StudentValidator,并集成類AbstractValidator<Student>,代碼如下:

?

public class StudentValidator : AbstractValidator<Student> {public StudentValidator(){RuleFor(x => x.Age).InclusiveBetween(10, 50);RuleFor(x => x.Name).NotEmpty().MaximumLength(5);} }

上述的驗證類中,要求Age大于10且小于50,Name不為空,且長度小于5。

最后,還需要將驗證類注冊到服務(wù)中。修改Startup的ConfigureServices,部分代碼如下:

?

services.AddControllers().AddFluentValidation(conf =>{conf.RegisterValidatorsFromAssemblyContaining<StudentValidator>();conf.RunDefaultMvcValidationAfterFluentValidationExecutes = false;});

上述代碼中,RegisterValidatorsFromAssemblyContaining方法的作用是掃描StudentValidator類所在的程序集中的所有驗證類,并注冊到服務(wù)中。

RunDefaultMvcValidationAfterFluentValidationExecutes為false時,會屏蔽掉系統(tǒng)默認(rèn)的模型驗證,如需兼容系統(tǒng)默認(rèn)的模型驗證,將RunDefaultMvcValidationAfterFluentValidationExecutes的值改為true即可。此參數(shù)默認(rèn)為true。

下面在Controller中,添加一個Action,代碼如下:

?

[HttpPost] public IActionResult Add([FromBody] Student student) {return Ok(student); }

打開swagger,訪問接口,響應(yīng)如下所示:

?

{"type": "https://tools.ietf.org/html/rfc7231#p-6.5.1","title": "One or more validation errors occurred.","status": 400,"traceId": "00-6331a76578228b4cb9044aa40f514bc9-89fd8547c1921340-00","errors": {"Age": ["'Age' 必須在 10 (包含)和 25 (包含)之間, 您輸入了 0。"],"Name": ["'Name' 必須小于或等于5個字符。您輸入了6個字符。"]} }

至此,在 ASP.NET Core中集成FluentValidation就完成了。但到現(xiàn)在為止,這和系統(tǒng)默認(rèn)的模型驗證并沒有區(qū)別。在文章的開頭筆者也提到過,FluentValidation不僅支持Controller中對模型進(jìn)行驗證,下面的代碼就是非Controller場景下的驗證。

?

public class DemoService {private readonly IValidator<Student> _studentValidator;public DemoService(IValidator<Student> studentValidator){_studentValidator = studentValidator;}public bool Run(Student student){var valid = _studentValidator.Validate(student);return valid.IsValid;} }

在上述代碼中,通過構(gòu)造函數(shù)注入的方式,獲取到了IValidator<Student>實例,在Run方法中只需要調(diào)用Validate方法,參數(shù)是需要驗證的對象,返回的對象就包含了驗證的是否通過以及不通過時,具體的錯誤信息。

?

基礎(chǔ)用法

?

內(nèi)置規(guī)則

FluentValidation內(nèi)置了多個常用的驗證器,下面簡單介紹幾個特別常用或容易出錯的驗證器。

NotNull 和 NotEmpty

NotNull是確保指定的屬性不為null,NotEmpty則表示確保指定的屬性不為null、空字符串或空白(值類型的默認(rèn)值,比如int類型的默認(rèn)值為0),如果int類型屬性設(shè)置NotEmpty驗證器,則當(dāng)值為0時,驗證是無法通過的。

NotEqual 和 Equal

NotEqual 和 Equal分別是不相等和相等驗證器,可與指定的值或者指定的屬性進(jìn)行比較。

MaximumLength、MinimumLength和Length

MaximumLength為最大長度驗證器,MinimumLength為最小長度驗證器,而Length則是二者的結(jié)合,需要注意的是,這三種驗證器僅對字符串有效,且不會驗證null,當(dāng)值為null時,則不對長度進(jìn)行驗證,所以使用長度驗證器時,建議結(jié)合NotNull一起使用。

?

LessThan、LessThanOrEqualTo、GreaterThan、GreaterThanOrEqualTo

上述的幾個驗證器為比較驗證器,僅適用于繼承IComparable接口的屬性,分別表示的是:小于、小于或等于、大于、大于或等于。

?

Matches

正則表達(dá)式驗證器,用于確保指定的屬性與給定的正則表達(dá)式匹配。

ExclusiveBetween和InclusiveBetween

示例代碼如下:

RuleFor(x => x.Id).ExclusiveBetween(1,10); RuleFor(x => x.Id).InclusiveBetween(1,10);

以上代碼均表示輸入的Id的值需要在1,10之間,而兩者的區(qū)別是,InclusiveBetween驗證器是包含頭和尾的,而ExclusiveBetween是不包含的,例如當(dāng)Id值為1時,ExclusiveBetween驗證失敗,但I(xiàn)nclusiveBetween則驗證成功。

覆蓋驗證器默認(rèn)的錯誤提示

在文章的開頭提到了,當(dāng)驗證Student的Age屬性不通過時,提示信息是:'Age' 必須在 10 (包含)和 25 (包含)之間, 您輸入了 0。

這個提示信息對于開發(fā)者來講,定位問題已經(jīng)很清晰了,但如果要在WebApi中講驗證的錯誤信息返回給前端,那么這個提示就會被用戶看到,則此錯誤信息就不太友好,FluentValidation提供了多種覆蓋錯誤提示的方式,下面就來一起看下。

?

占位符

我們可以將驗證Age的代碼改為如下所示:

?

RuleFor(x => x.Age).InclusiveBetween(10, 25).WithMessage("年齡必須在{From}到{To}之間");

當(dāng)驗證不通過時,輸出的錯誤信息則為:年齡必須在10到25之間。

程序自動將{From}和{To}進(jìn)行了替換。每個驗證器的占位符都不一樣,有關(guān)占位符的完整列表,請查看官方文檔?https://docs.fluentvalidation.net/en/latest/built-in-validators.html。

?

覆蓋屬性名稱

此方法是將屬性的名稱使用指定的字符串替換,如下所示:

?

RuleFor(x => x.Age).InclusiveBetween(10, 25).WithName("年齡");

當(dāng)發(fā)生錯誤時,會自動將系統(tǒng)默認(rèn)的錯誤提示信息中的"Age"替換為"年齡"

默認(rèn)情況下,When或者Otherwise將應(yīng)用于鏈?zhǔn)秸{(diào)用的所有前置的驗證器,如果只希望條件引用于前面的第一個驗證器,則必須使用ApplyConditionTo.CurrentValidator顯示指定

?

RuleFor(x => x.Age).GreaterThan(10).LessThan(20).When(x => x.Sex == 2,ApplyConditionTo.CurrentValidator);

上述的代碼,如果不加ApplyConditionTo.CurrentValidator,則當(dāng)Sex等于2時,則要求Age大于10且小于20。而Sex不等于2時,則不作任何驗證。如果加上ApplyConditionTo.CurrentValidator,則Age大于10的驗證跟Sex的值沒有任何關(guān)系了,程序會始終驗證Age是否大于10

?

帶條件的驗證規(guī)則

使用When方法可控制規(guī)則執(zhí)行的條件。例如,國家的法定結(jié)婚年齡為女性20歲,則驗證年齡屬性時,只有當(dāng)性別為女時,才對年齡大于等于20進(jìn)行校驗。

?

RuleFor(x => x.Age).GreaterThan(20).When(x => x.Sex == 2);

相反的,Unless表示的是當(dāng)指定條件不滿足時,才執(zhí)行校驗。

RuleFor(x => x.Age).GreaterThan(20).Unless(x => x.Sex == 2);

上述代碼表示當(dāng)Sex值不為2時,校驗Age是否大于等于20

如果需要為多個驗證規(guī)則指定相同的條件,可以調(diào)用When的頂級方法,而不是在規(guī)則末尾調(diào)用When方法。

?

When(x => x.Sex == 2, () => {RuleFor(x => x.Name).Must(x => !x.EndsWith("國慶"));RuleFor(x => x.Age).LessThan(30); });

上述代碼表示是,當(dāng)Sex等于2時,Age需要小于30,并且名字不能以"國慶"結(jié)尾。

將Otherwise方法鏈接到When調(diào)用,表示W(wǎng)hen條件不滿足時,執(zhí)行的驗證規(guī)則。

?

When(x => x.Sex == 2, () => {RuleFor(x => x.Name).Must(x => x.EndsWith("國慶"));RuleFor(x => x.Age).LessThan(30); }).Otherwise(() => {RuleFor(x => x.Age).LessThan(50); });

上述代碼中的Otherwise方法表示的是,當(dāng)Sex不等于2時,則Age需要小于50

?

鏈?zhǔn)秸{(diào)用

當(dāng)一個屬性使用多個驗證規(guī)則時,可將多個驗證器鏈接在一起,比如,Student類的Name屬性不能為空,并且,長度需要小于10,則對應(yīng)的代碼為:

?

public StudentValidator() {RuleFor(x =>x.Name).NotEmpty().MaximumLength(10); }

CascadeMode

CascadeMode是一個枚舉類型的屬性,有兩個選項:Continue和Stop

如果設(shè)置為Stop,則檢測到失敗的驗證,則立即終止,不會繼續(xù)執(zhí)行剩余屬性的驗證。默認(rèn)值為Continue

CascadeMode = CascadeMode.Stop; RuleFor(x => x.Name).NotEmpty().MaximumLength(10); RuleFor(x => x.NickName).NotEmpty().MaximumLength(10);

如上述代碼所示,當(dāng)Name值不滿足要求時,則會停止對NickName的校驗

依賴規(guī)則

默認(rèn)情況下,FluentValidation 中的所有規(guī)則都是獨(dú)立的,不能彼此影響。這是異步驗證工作所必需的,也是必要的。但是,在某些情況下,您可能希望確保某些規(guī)則僅在另一個規(guī)則完成之后執(zhí)行。您可以使用DependentRules它來做到這一點。

比如,只有身高超過130的兒童,才需要驗證是否購票,則可以通過如下的代碼實現(xiàn):

RuleFor(x => x.Height).GreaterThan(130).DependentRules(() => {RuleFor(x => x.HasTicket).NotEmpty(); });

?

高級用法

異步驗證

在某些情況下,你可能希望定義異步規(guī)則,比如從數(shù)據(jù)庫或者外部api判斷。

?

public StudentValidator(IStudentService studentService) {_studentService = studentService;RuleFor(x => x.Name).MustAsync(async (name, token) => await _studentService.CheckExist(name)); }

上述代碼中,通過一個異步方法的返回值驗證Name屬性。
另外,如果在非Controller場景下使用,則必須調(diào)用ValidateAsync方法進(jìn)行驗證。

轉(zhuǎn)換值

您可以在對屬性值執(zhí)行驗證之前使用 Transform方法轉(zhuǎn)換屬性值。

RuleFor(x => x.Weight).Transform(x => int.TryParse(x, out int val)?(int?)val:null).GreaterThan(10);

上述代碼先試圖將string類型轉(zhuǎn)換成int類型,如果轉(zhuǎn)換成功則對轉(zhuǎn)換后的值做大于驗證。如果轉(zhuǎn)換失敗,則不做驗證。

?

回調(diào)

如果驗證失敗,可以使用回調(diào)做一些操作。

?

RuleFor(x => x.Weight).NotEmpty().OnFailure(x =>{Console.WriteLine("驗證失敗");});

預(yù)驗證

如果需要每次調(diào)用驗證器前運(yùn)行特定代碼,可以通過重寫PreValidate方法來做到這一點。

public class StudentValidator : AbstractValidator<Student> {public StudentValidator(){RuleFor(x => x.Weight).NotEmpty();}protected override bool PreValidate(ValidationContext<Student> context,ValidationResult result){if (context.InstanceToValidate == null) return true;result.Errors.Add(new ValidationFailure("", "實體不能為null"));return false;} }

?


福祿ICH.架構(gòu)出品

作者:福爾斯

2021年3月

總結(jié)

以上是生活随笔為你收集整理的客官,.NETCore无代码侵入的模型验证了解下的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。