文章出處

問題

  想要 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

  還有另一種方法,就是可以使用一個叫做 FluentValidationNuGet 中可以下載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.ModelbindingModelStateDictionary 暴露了IsValid 屬性,這個屬性可以用來檢查 Action Model 驗證的狀態。

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

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

 

代碼

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

RequiredAttributeMaxLengthAttribute 

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.");
        }
    }
}




文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()