【ASP.NET Web API教程】6.4 模型驗證

本文是Web API系列教程的第6.4小節html

6.4 Model Validation
6.4 模型驗證

摘自:http://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-apiweb

By Mike Wasson|July 20, 2012
做者:Mike Wasson | 2012-6-20json

When a client sends data to your web API, often you want to validate the data before doing any processing.
當客戶端發送數據給你的Web API時,你一般但願在作其它處理以前先對數據進行驗證。api

6.4.1 Data Annotations
6.4.1 數據註解

In ASP.NET Web API, you can use attributes from the System.ComponentModel.DataAnnotations namespace to set validation rules for properties on your model. Consider the following model:
在ASP.NET Web API中,你可使用System.ComponentModel.DataAnnotations命名空間的註解屬性來設置模型屬性的驗證規則。考慮如下模型:安全

public class Product
{
    public int Id { get; set; }
[Required] public string Name { get; set; } public decimal Price { get; set; }
[Range(0,999)] public double Weight { get; set; } }

If you have used model validation in ASP.NET MVC, this should look familiar. The Required attribute says that the Name property must not be null. The Range attribute says that Weight must be between zero and 999.
若是你曾在ASP.NET MVC中使用過模型驗證,這看上去是相似的。Required註解屬性說明Name屬性必須不爲空。Range註解屬性說明Weight必須在0-999之間。mvc

Suppose that a client sends a POST request with the following JSON representation:
假設客戶端發送了一個帶有下列JSON表示的POST請求:app

{ "Id":4, "Price":2.99, "Weight":5 }

You can see that the client did not include the Name property, which is marked as required. When Web API converts the JSON into a Product instance, it validates the Product against the validation attributes. In your controller action, you can check whether the model is valid:
你能夠看出,客戶端並未包含被標記成required的Name屬性。當Web API將該JSON轉換成Product實例時,它會根據這些驗證註解屬性對Product進行驗證。在控制器動做中,你能夠檢查該模型是否有效:asp.net

public class ProductsController : ApiController
{
    public HttpResponseMessage Post(Product product)
    {
        if (ModelState.IsValid)
        {
            // Do something with the product (not shown).
            // 用product作一些事(未表示出來)
return new HttpResponseMessage(HttpStatusCode.OK); } else { return new HttpResponseMessage(HttpStatusCode.BadRequest); } } }

Model validation does not guarantee that client data is safe. Additional validation might be needed in other layers of the application. (For example, the data layer might enforce foreign key constraints.) The tutorial Using Web API with Entity Framework explores some of these issues.
模型驗證並不保證客戶端數據是安全的。在應用程序的其它層面可能會須要附加驗證(例如,數據層可能會強制外鍵約束)。「Using Web API with Entity Framework(與Entity Framework一塊兒使用Web API)(本系列教程的第2章)」教程考察一些此類問題。ide

"Under-Posting": Under-posting happens when the client leaves out some properties. For example, suppose the client sends the following:
Under-Posting(遞交不足)」:當客戶端遺漏了某些屬性時,便會發生「Under-posting」。例如,假設客戶端發送以下:post

{"Id":4, "Name":"Gizmo"}

Here, the client did not specify values for Price or Weight. The JSON formatter assigns a default value of zero to the missing properties.
此處,客戶端並未指定Price或Weight的值。JSON格式化器會將默認值(這裏是零)賦給這些缺失的屬性。

圖6.4-1

圖6.4-1

The model state is valid, because zero is a valid value for these properties. Whether this is a problem depends on your scenario. For example, in an update operation, you might want to distinguish between "zero" and "not set." To force clients to set a value, make the property nullable and set the Required attribute:
此時模型的狀態是有效的,由於零是這些屬性的有效值。這是不是一個問題取決於你所處的場景。例如,在一個更新操做中,你可能但願區分出「零」與「未設置」。爲了強迫客戶端要設置一個值,將該屬性構形成nullable(可空的),並設置Required註解屬性:

[Required]
public decimal? Price { get; set; }

"Over-Posting": A client can also send more data than you expected. For example:
Over-Posting(過份遞交)」:客戶端也可能發送比指望還多的數據。例如:

{"Id":4, "Name":"Gizmo", "Color":"Blue"}

Here, the JSON includes a property ("Color") that does not exist in the Product model. In this case, the JSON formatter simply ignores this value. (The XML formatter does the same.) Over-posting causes problems if your model has properties that you intended to be read-only. For example:
此處,JSON包含了Product模型中存在的屬性(「Color」)。在這種狀況下,JSON格式化器會簡單地忽略該值(XML格式化器卻不一樣)。若你的模型具備只讀屬性,Over-posting會產生問題。例如:

public class UserProfile
{
    public string Name { get; set; }
    public Uri Blog { get; set; }
    public bool IsAdmin { get; set; }  // uh-oh!(啊哦!)
}

You don't want users to update the IsAdmin property and elevate themselves to administrators! The safest strategy is to use a model class that exactly matches what the client is allowed to send:
若是你不想讓用戶對IsAdmin屬性進行更新,並將其提高給管理員。最安全的策略是使用一個與容許客戶端發送嚴格匹配的模型類:

public class UserProfileDTO
{
    public string Name { get; set; }
    public Uri Blog { get; set; }
    // Leave out "IsAdmin"
    // 略去了"IsAdmin"
}

Brad Wilson's blog post "Input Validation vs. Model Validation in ASP.NET MVC" has a good discussion of under-posting and over-posting. Although the post is about ASP.NET MVC 2, the issues are still relevant to Web API.
Brad Wilson的博客文檔「Input Validation vs. Model Validation in ASP.NET MVC(ASP.NET MVC中的輸入驗證與模型驗證)」對under-posting和over-posting有很好的討論。雖然這篇博文是關於ASP.NET MVC 2的,但這種問題仍然關係到Web API。

6.4.2 Handling Validation Errors
6.4.2 處理驗證錯誤

Web API does not automatically return an error to the client when validation fails. It is up to the controller action to check the model state and respond appropriately.
當驗證失敗時,Web API並不會自動地將錯誤返回給客戶端。這取決於控制器動做對模型狀態及響應進行適當的檢查。

You can also create an action filter to check the model state before the controller action is invoked. The following code shows an example:
你也能夠建立一個動做過濾器,以便在控制器動做被調用以前,檢查模型的狀態。如下代碼演示了一個例子:

using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.Web.Http.ModelBinding;
public class ModelValidationFilterAttribute : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { if (actionContext.ModelState.IsValid == false) { // Return the validation errors in the response body. // 在響應體中返回驗證錯誤 var errors = new Dictionary<string, IEnumerable<string>>(); foreach (KeyValuePair<string, ModelState> keyValue in actionContext.ModelState) { errors[keyValue.Key] = keyValue.Value.Errors.Select(e => e.ErrorMessage); }
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, errors); } } }

If model validation fails, this filter returns an HTTP response that contains the validation errors. In that case, the controller action is not invoked.
若是模型驗證失敗,此過濾器會返回一個含有驗證錯誤的HTTP響應。在此狀況下,不會調用控制器動做。

HTTP/1.1 400 Bad Request
Server: ASP.NET Development Server/10.0.0.0
Date: Fri, 20 Jul 2012 21:42:18 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 239
Connection: Close
{ "product": [ "Required property 'Name' not found in JSON. Line 1, position 18." ],
"product.Name": [ "The Name field is required." ],
"product.Weight": [ "The field Weight must be between 0 and 999." ] }

If you are using the latest Web API source on CodePlex, you can use the HttpError class to return validation errors to the client. The HttpError class is not available in the RC release.
若是你正在使用CodePlex上最新版的Web API,可使用HttpError類將驗證錯誤返回給客戶端。HttpError類在RC版(指Web API的預覽版)中無效。

You can apply this filter globally to all Web API controllers. In the Application_Start method, add the filter to the HttpConfiguration.Filters collection:
你能夠將此過濾器全局性地運用於全部Web API控制器。在Application_Start方法中,將此過濾器添加到HttpConfiguration.Filters集合:

protected void Application_Start()
{
    // ...
GlobalConfiguration.Configuration.Filters.Add(new ModelValidationFilterAttribute()); }

Alternatively, you can apply it to individual controllers or controller actions, by adding the filter as an attribute:
另外一種可選辦法是,經過將此過濾器做爲註解屬性進行添加,你能夠將它運用於個別控制器或控制器動做:

public class ProductsController : ApiController
{
    [ModelValidationFilter]
    public HttpResponseMessage Post(Product product)
    {
        // ...
    }
}

看完此文若是以爲有所收穫,請給個推薦。 你的推薦是我繼續下去的動力,也會讓更多人關注並獲益,這也是你的貢獻。

相關文章
相關標籤/搜索