程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> [水煮 ASP.NET Web API2 方法論](1-6)Model Validation,api2validation

[水煮 ASP.NET Web API2 方法論](1-6)Model Validation,api2validation

編輯:關於.NET

[水煮 ASP.NET Web API2 方法論](1-6)Model Validation,api2validation


問題

  想要 ASP.NET Web API 執行模型驗證,同時可以和 ASP.NET MVC 共享一些驗證邏輯。

解決方案

  ASP.NET Web API 與 ASP.NET MVC 支持一樣的驗證機制,都是通過System.ComponentModel.DataAnnoataions 的屬性驗證。使用框架提供的相關驗證屬性,已足夠來用來驗證模型。

想要更細粒度的驗證,我們可以選擇在我們的模型中實現 IValudateObject(來自於System.ComponentModel.DataAnnotations)。如果所有的屬性都驗證通過,ASP.NET Web API 將會調用接口的Validate 方法,在這裡我們可以進行更進一步的進行實體驗證。這是和 MVC 裡面的行為一樣,並且,我們甚至可以在 Web API 和 MVC 中使用同一個 DTO。

  還有另一種方法,就是可以使用一個叫做 FluentValidation(NuGet 中可以下載FluentValidation)的第三方程序庫,他可以構建更強大的驗證場景。在這樣的情況下,我們仍然需在我們的模型中實現 IValidateObject 接口,同時需要依賴於FluentValidation 驗證器,而不是內嵌的驗證邏輯。

小提示 ASP.NET Web API 的驗證行為在跨宿主機上是相同的。

工作原理

  為了從 HTTP 請求 Body 中讀取的模型並執行驗證,ASP.NET Web API 依賴於一個 IBodyModelValidator 的服務。接口的大致描述如清單 1-17 所示,然而,他是一個可替代的服務,正常情況下,默認實現(DefaultBodyModelValidator)足夠我們使用,在HttpConfiguration 被設置為自啟動。

清單 1-17. IBodyModelValidator 接口

1 2 3 4 5 public interface IBodyModelValidator {     bool Validate(object model, Type type, ModelMetadataProvider metadataProvider,     HttpActionContext actionContext, string keyPrefix); }

 

 

  有一個叫做FormatrtParameterBinding 的服務,在 HTTP 請求 Body 綁定到 Action 參數的處理請求時,DefaultBodyModelValidator 的 Validate 方法會被調用。對於驗證程序,他會遞歸驗證整個對象圖譜,驗證每一個屬性以及嵌套屬性。Web API 通過使用DataAnnotationModelValidatorProviderr 來支持聲明。如果我們的模型使用WCF 方式的 DataMemberAttribute 聲明,那麼,我們需要使用框架的 DataMemberValidatorProvider。

  最後,我們的模型可以實現IValidatableObject 接口,這個接口只暴露了一個簡單的方法如清單1-18所示。如果實現了接口,那就需要我們自己提供額外的驗證邏輯。只要所有的屬性驗證通過,ASP.NET Wwb API 就會調用IValidateableObject接口的 Validate 方法,

 

清單1-18. IValidateableObject 接口的定義

1 2 3 4 public interface IValidateableObject {     IEnumerable<ValidationResult> Validate(ValidationContext validationContext); }

 

 

  驗證結果是通過 ASP.NET Web API 的  ModelStateDictionary 形式表示,在這裡 ModelState 也是可以用的。這個和 ASP.NET MVC 中的概念是完全一樣的,但是使用的對象是不同的,因為 Web API 使用自己版本的System.Web.Http.Modelbinding。ModelStateDictionary 暴露了IsValid 屬性,這個屬性可以用來檢查 Action 內Model 驗證的狀態。

  聲明的驗證機制也很好的整合到了 ASP.NET Web API Help Page,可以提供對 API 語義上的描述。我們將會在7-11 的時候詳細討論他。

  小提示 在 API 中最好的做法是使用不同的模型作為 Request 和Response 實體。例如,實體 ID 一般僅僅是 Response 模型需要的,如果 Request 中需要的話,是可以從 URI 中拿到的。

 

代碼

  清單 1-19 展示了一個模型有多種驗證的情況:

RequiredAttribute,MaxLengthAttribute 和

RangeAttribute。接下來,我們就可以利用 ModelState 來驗證 Controller 中的驗證狀態,同時響應適當的提示信息給調用端。

清單 1-19. 簡單的 Web API 模型驗證

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class Album {     public int Id { getset; }     [Required(ErrorMessage = "{0} is required")]     [MaxLength(30)]     public string Artist { getset; }     [Required(ErrorMessage = "{0} is required")]     [MaxLength(40)]     public string Title { getset; }     [Range(0, 10, ErrorMessage = "{0} in the range of {1}-{2} is required.")]     public int Rating { getset; } } public class AlbumController : ApiController {     public HttpResponseMessage Post(Album album)     {         if (!ModelState.IsValid)         {             throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest,             ModelState));         }         //omitted for brevity     } }

 

 

  負責處理 ModelState 代碼的一般驗證可以很容易從 Controller 提取到成公共的部分,使其可以被很好的重用,不過這一部分我們將在 5-4 的時候再詳細介紹。

  現在,我們考慮一下這個場景,如果我們要在模型上增加增加兩個額外的屬性 Rating 和 Starred,同時擴展模型驗證,驗證的要求是這兩個屬性至少有一個是必填的。雖然,在兩個屬性之間糾纏的驗證很難使用聲明的方式來表示,但是,不要忘記 IValidateableObject 可以幫我們。我們可以使用接口中的 Validata 的方法去檢查整個模型的狀態,同時返回相應的 ValidationResult。我們要做的修改如清單 1-20 所示的代碼。

 

清單 1-20. 修改 ASP.NET Web API 依賴於 IValidateableObject 的驗證

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class Album : IValidatableObject {     public int Id { getset; }        [Required(ErrorMessage = "{0} is required")]     [MaxLength(30)]     public string Artist { getset; }        [Required(ErrorMessage = "{0} is required")]     [MaxLength(40)]     public string Title { getset; }        public int? Rating { getset; }     public bool? Starred { getset; }        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)     {         if (!(Rating.HasValue && Rating > 0 && Rating < 10) || (Starred.HasValue && Starred.Value))         {             yield return new ValidationResult("You must set either the Rating in the 0-9 range orStarred flag.");         }     } }


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved