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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

验证规则构建神器 FluentValidation.md

發布時間:2023/12/4 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 验证规则构建神器 FluentValidation.md 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上一篇文章《MediatR在.NET應用中的實踐》中,我們在講MediatR的管線內容時,提到過可以在管線中增加 Command/Query 的驗證。今天我來帶領大家了解一個.NET技術領域中很「流行」的強類型驗證規則構建庫:FluentValidation。

FluentValidation 簡介

這么多年的開發工作中,我一直很喜歡「Fluent」編程風格,所以對Fluent開頭或風格上比較Fluent的各種類庫工具也都蠻喜歡。比如.NET領域的:FluentAssertions、FluentMigrator、FluentFTP、FluentScheduler、FluentEmail以及Flurl等等。以后我會另起幾篇文章介紹一下他們。

「FluentValidation」 是一個面向 .NET 應用的強類型驗證規則構建庫,且使用 Apache-2.0 協議開源在 https://github.com/FluentValidation/FluentValidation 。官方網站是: https://fluentvalidation.net 。

官網直接在首屏以源代碼方式來展現他:直觀、簡潔、很 Fluent的顯著特:

public?class?CustomerValidator?:?AbstractValidator<Customer>?{public?CustomerValidator()?{RuleFor(x?=>?x.Surname).NotEmpty();RuleFor(x?=>?x.Forename).NotEmpty().WithMessage("Please?specify?a?first?name");RuleFor(x?=>?x.Discount).NotEqual(0).When(x?=>?x.HasDiscount);RuleFor(x?=>?x.Address).Length(20,?250);RuleFor(x?=>?x.Postcode).Must(BeAValidPostcode).WithMessage("Please?specify?a?valid?postcode");}private?bool?BeAValidPostcode(string?postcode)?{//?custom?postcode?validating?logic?goes?here} }

簡單理解一下其中的幾個關鍵要素:

  • 這是一個針對Customer類型對象的驗證規則

  • 規則驗證器必須繼承自 AbstractValidator<T>,其中的T就是你所希望在這個驗證器中驗證的實際數據類型;

  • 規則驗證器通過構造函數直接進行規則設定;

  • 通常針對一個屬性的驗證規則我們直接以RuleFor(x => x.*** )作為代碼開頭進行流暢的規則驗證;

  • 內置規則方法已經非常豐富:NotEmpty、NotEqual、Length等,也可以使用 Must 進行自定義設置;

  • 可以用When設定規則驗證的前提;

  • 默認常見內置規則,都有統一內置的驗證不通過的消息;可通過WithMessage設置獨立的驗證不通過的消息;

  • FluentValidation 的相關包

    「FluentValidation」 的驗證規則設置能力非常強大,下圖中是目前所有內置的規則驗證:用之前,我們通常需要引用的幾個包:

    • 「FluentValidation」 核心包,必須的

    • 「FluentValidation.DependencyInjectionExtensions」 當你需要在依賴注入的場景下用的時候,這是必須的

    • 「FluentValidation.AspNetCore」 當你需要在ASP.NET Core相關業務場景用的時候,最好也引用一下這個.

    ?

    「注意」 FluentValidation.AspNetCore 中以及包含了對 FluentValidation 和 FluentValidation.DependencyInjectionExtensions 的依賴。

    ?

    ASP.NET Core 中啟用FluentValidation的

    默認情況下的ASP.NET或ASP.NET Core,Controler 中 Action 的參數會被自動綁定和驗證通過 DataAnnotation 相關的 Attribute 約定的驗證規則,但是 DataAnnotations 應對簡單的驗證還行,如果需要分不同場景或者有前提條件等的時候,他就明顯力不從心了。「FluentValidation」 則可以針對我們各種需求進行驗證,所以我建議大家在實際項目中多考慮使用之。

    入門使用

    public?void?ConfigureServices(IServiceCollection?services)? {//?或者是?services.AddControllers(setup?=>services.AddMvc(setup?=>?{//...mvc?setup...}).AddFluentValidation(); }

    通過上面的代碼啟用 FluentValidation 后,MVC 將使用 FluentValidation 來驗證 Controller 上 Action 中綁定的 Model 對象。

    ?

    「注意:」 作為 .NET 6 一部分的 Minimal API 不支持自動驗證

    ?

    此時你可能會問,他怎么知道用哪個驗證規則啊?嗯,上面這種簡單啟用時,驗證規則也需要通過顯性的代碼進行驗證規則注入:

    services.AddTransient<IValidator<Customer>,?CustomerValidator>();

    可以想象,如果你有很多的 Model 類型和對應的驗證規則設置,這樣一個一個的注冊,會心態崩潰,最終放棄的。

    自動注冊

    我們可以根據需要通過下面兩種方式來進行自動化的注冊:

    //?掃描并注冊?Startup?類型所在程序集中的?Validator?驗證器 services.AddValidatorsFromAssemblyContaining(typeof(Startup));//?掃描并注冊指定名稱程序集中的所有?Validator?驗證器 services.AddValidatorsFromAssembly(Assembly.Load("SomeAssembly"));

    嗯,很好,這樣我就可以隨意增加新的 Validator ,而不必擔心忘記注冊了。

    進階設置

    默認情況下,在執行 FluentValidation 之后,任何其他驗證器提供程序也將有機會執行,這也就意味著您可以將 FluentValidation 與 DataAnnotations 屬性(或其他 ModelValidatorProvider)混合使用。

    但我們可能并不想混亂的開啟那么多驗證,造成對同一個 Model 有多套驗證,一旦發現不符合業務預期,要到處找驗證是怎么回事兒。所以推薦大家只使用其一,比如在啟用 FluentValidation 時禁用 DataAnnotations:

    AddFluentValidation(fv?=>?{//?禁用?MVC?默認的?DataAnnotations?驗證fv.DisableDataAnnotationsValidation?=?true; });

    這樣,我們的 ASP.NET Core 就會忽略默認的 DataAnnotations 驗證。

    隱式子屬性驗證

    如果你詳細閱讀過 FluentValidation 的官方文檔,你會了解到它帶有子屬性驗證的場景。也就是一個 Model 的屬性類型,是另外一個設置過驗證規則的類。我們想讓子屬性也在父對象被驗證時同時被驗證,還懶得在驗證規則中明文通過SetValidator設置子屬性驗證,怎么辦?

    services.AddMvc().AddFluentValidation(fv?=>? { //?遞歸檢查所有子屬性的驗證規則fv.ImplicitlyValidateChildProperties?=?true; });

    雖然這樣可以讓你偷懶,但是我不建議這樣做,因為驗證器不只是 MVC 中需要的。我們在驗證規則中應該明文設置子屬性驗證規則,這樣也可針對不同的場景和業務要求讓規則「顯性」。

    對于數據集合,默認情況下,您必須創建特定的集合驗證器或啟用隱式子屬性驗證來驗證屬于集合類型的模型。例如,定義一個繼承自 AbstractValidator<List<Customer>> 的驗證器。啟用隱式子屬性驗證(見上文)后,您不必顯式創建集合驗證器類,因為集合中的每個 customer 元素都將被自動驗證。但 Customer 對象上的任何子屬性也將自動驗證!如果你不希望這樣,可以選擇僅對根集合元素啟用隱式驗證:

    services.AddMvc().AddFluentValidation(fv?=>? {fv.ImplicitlyValidateRootCollectionElements?=?true; });?

    再次聲明,我不建議在 MVC 中啟用隱式的子屬性驗證,這給你的實際業務會帶來不確定性和不必要的性能損害。

    ?

    規則集 RuleSet

    規則集允許您將驗證規則組合在一起,這些規則可以作為一個組一起執行:

    public?class?PersonValidator?:?AbstractValidator<Person>?{public?PersonValidator()?{RuleSet("Names",?()?=>?{RuleFor(x?=>?x.Surname).NotNull();RuleFor(x?=>?x.Forename).NotNull();});RuleFor(x?=>?x.Id).NotEqual(0);} }

    這樣在手動驗證等場景下,可以通過代碼指定僅驗證規則集中的規則,而忽略其他規則:

    var?validator?=?new?PersonValidator(); var?person?=?new?Person(); var?result?=?validator.Validate(person,?options?=>?options.IncludeRuleSets("Names"));

    在 MediatR 的管線中對Request進行自動驗證

    正如開頭我們說的,MediatR 可以通過管線對 Request 進行驗證,這里我們也使用 FluentValidation 作為 MediatR 的默認驗證。

    首先定義驗證管線:

    public?class?RequestValidationBehavior<TRequest,?TResponse>?:?IPipelineBehavior<TRequest,?TResponse>where?TRequest?:?IRequest<TResponse> {private?readonly?IEnumerable<IValidator<TRequest>>?_validators;public?RequestValidationBehavior(IEnumerable<IValidator<TRequest>>?validators){_validators?=?validators;}public?Task<TResponse>?Handle(TRequest?request,?CancellationToken?cancellationToken,?RequestHandlerDelegate<TResponse>?next){var?failures?=?_validators.Select(v?=>?v.Validate(request)).SelectMany(result?=>?result.Errors).Where(f?=>?f?!=?null).ToList();if?(failures.Count?!=?0){throw?new?ValidationException(failures);}return?next();} }

    然后注冊管線:

    services.AddTransient(typeof(IPipelineBehavior<,>),?typeof(RequestValidationBehavior<,>));

    「注意」 建議驗證管線加在其他自定義管線之前,使得每次通過 Mediator Send 一個 Request 時,都會優先執行驗證,驗證不通過就沒后面管線什么事兒了。

    最后根據需要在你自己的 ASP.NET Core 自定義異常處理管線中增加針對 ValidationException 的統一處理,下面是我針對 WebAPI 的樣例代碼參考:

    public?class?CustomExceptionHandlerMiddleware {private?readonly?RequestDelegate?_next;private?readonly?ILogger<CustomExceptionHandlerMiddleware>?_logger;public?CustomExceptionHandlerMiddleware(RequestDelegate?next,?ILogger<CustomExceptionHandlerMiddleware>?logger){_next?=?next;_logger?=?logger;}public?async?Task?Invoke(HttpContext?context){try{await?_next(context);}catch?(Exception?ex){await?HandleExceptionAsync(context,?ex);}}private?Task?HandleExceptionAsync(HttpContext?context,?Exception?exception){var?code?=?HttpStatusCode.InternalServerError;var?result?=?string.Empty;switch?(exception){case?ValidationException?validationException:code?=?HttpStatusCode.BadRequest;result?=?JsonConvert.SerializeObject(new?{?code,?message?=?validationException.Failures.First().Value.FirstOrDefault()????validationException.Message,?details?=?validationException.Failures?});break;//?case?其他需要統一處理的異常}context.Response.ContentType?=?"application/json";context.Response.StatusCode?=?(int)code;if?(string.IsNullOrEmpty(result)){_logger.LogError("發生服務器端異常,{@exception}",?exception);result?=?JsonConvert.SerializeObject(new?{?code,?message?=?exception.Message?});}return?context.Response.WriteAsync(result);} }

    結束語

    FluentValidation 遠比我在文中介紹的要強大的多,小小的一篇公眾號不可能把它完全講的面面俱到,建議你通過本文了解一些特性后,去讀一下官方文檔。如果還從未用過,建議你寫幾個demo嘗試一下,「實踐出真知」

    總結

    以上是生活随笔為你收集整理的验证规则构建神器 FluentValidation.md的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。