<sub id="gqw76"><listing id="gqw76"></listing></sub>
      <sub id="gqw76"><listing id="gqw76"></listing></sub>

    1. <form id="gqw76"><legend id="gqw76"></legend></form>
    2. 客官,.NETCore無代碼侵入的模型驗證了解下

      背景

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

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

      在WebApi中,當請求接口時,程序會自動對模型進行驗證,如無法驗證通過,則會直接終止后續的邏輯執行,并響應400狀態碼,響應內容如下所示:

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

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

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

      下面就來和筆者一起了解下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; }
      }
      

      然后創建類StudentValidator,并集成類AbstractValidator,代碼如下:

      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。

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

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

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

      RunDefaultMvcValidationAfterFluentValidationExecutes為false時,會屏蔽掉系統默認的模型驗證,如需兼容系統默認的模型驗證,將RunDefaultMvcValidationAfterFluentValidationExecutes的值改為true即可。此參數默認為true。

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

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

      打開swagger,訪問接口,響應如下所示:

      {
        "type": "https://tools.ietf.org/html/rfc7231#section-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就完成了。但到現在為止,這和系統默認的模型驗證并沒有區別。 在文章的開頭筆者也提到過,FluentValidation不僅支持Controller中對模型進行驗證,下面的代碼就是非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;
          }
      }
      

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

      基礎用法

      內置規則

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

      NotNull 和 NotEmpty

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

      NotEqual 和 Equal

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

      MaximumLength、MinimumLength和Length

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

      LessThan、LessThanOrEqualTo、GreaterThan、GreaterThanOrEqualTo

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

      Matches

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

      ExclusiveBetween和InclusiveBetween

      示例代碼如下:

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

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

      覆蓋驗證器默認的錯誤提示

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

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

      占位符

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

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

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

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

      覆蓋屬性名稱

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

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

      當發生錯誤時,會自動將系統默認的錯誤提示信息中的"Age"替換為"年齡"

      默認情況下,When或者Otherwise將應用于鏈式調用的所有前置的驗證器,如果只希望條件引用于前面的第一個驗證器,則必須使用ApplyConditionTo.CurrentValidator顯示指定

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

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

      帶條件的驗證規則

      使用When方法可控制規則執行的條件。例如,國家的法定結婚年齡為女性20歲,則驗證年齡屬性時,只有當性別為女時,才對年齡大于等于20進行校驗。

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

      相反的,Unless表示的是當指定條件不滿足時,才執行校驗。

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

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

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

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

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

      將Otherwise方法鏈接到When調用,表示When條件不滿足時,執行的驗證規則。

      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方法表示的是,當Sex不等于2時,則Age需要小于50

      鏈式調用

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

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

      CascadeMode

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

      如果設置為Stop,則檢測到失敗的驗證,則立即終止,不會繼續執行剩余屬性的驗證。默認值為Continue

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

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

      依賴規則

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

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

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

      高級用法

      異步驗證

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

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

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

      轉換值

      您可以在對屬性值執行驗證之前使用 Transform方法轉換屬性值。

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

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

      回調

      如果驗證失敗,可以使用回調做一些操作。

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

      預驗證

      如果需要每次調用驗證器前運行特定代碼,可以通過重寫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.架構出品

      作者:福爾斯

      2021年3月

      posted @ 2021-03-09 19:11  福祿網絡研發團隊  閱讀(907)  評論(7編輯  收藏  舉報
      最新chease0ldman老人|无码亚洲人妻下载|大香蕉在线看好吊妞视频这里有精品www|亚洲色情综合网

        <sub id="gqw76"><listing id="gqw76"></listing></sub>
        <sub id="gqw76"><listing id="gqw76"></listing></sub>

      1. <form id="gqw76"><legend id="gqw76"></legend></form>