Asp.Net Web API 2第十五課——Model Validation(模型驗證)


前言

閱讀本文之前,您也可以到Asp.Net Web API 2 系列導航進行查看 http://www.cnblogs.com/aehyok/p/3446289.html

本文參考鏈接文章地址http://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api

當客戶端發送數據給你的Web API時,你通常希望在做其它處理之前先對數據進行驗證。

Data Annotations——數據注解

 在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; }
}

如果你曾在ASP.NET MVC中使用過模型驗證,這看上去是類似的。Required注解屬性說明Name屬性必須不為空。Range注解屬性說明Weight必須在0-999之間。

假設客戶端發送了一個帶有下列JSON表示的POST請求:

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

你可以看出,客戶端並未包含被標記成required的Name屬性。當Web API將該JSON轉換成Product實例時,它會根據這些驗證注解屬性對Product進行驗證。在控制器動作中,你可以檢查該模型是否有效:

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

模型驗證並不保證客戶端數據是安全的。在應用程序的其它層面可能會需要附加驗證(例如,數據層可能會強制外鍵約束)。

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

此處,客戶端並未指定Price或Weight的值。JSON格式化器會將默認值(這里是零)賦給這些缺失的屬性。

Under-Posting(遞交不足)”:當客戶端遺漏了某些屬性時,便會發生“Under-posting”。例如,假設客戶端發送如下:

此時模型的狀態是有效的,因為零是這些屬性的有效值。這是否是一個問題取決於你所處的場景。例如,在一個更新操作中,你可能希望區分出“零”與“未設置”。為了強迫客戶端要設置一個值,將該屬性構造成nullable(可空的),並設置Required注解屬性:

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

Over-Posting(過份遞交)”:客戶端也可能發送比期望還多的數據。例如:

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

此處,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!(啊哦!)
}

如果你不想讓用戶對IsAdmin屬性進行更新,並將其提升給管理員。最安全的策略是使用一個與允許客戶端發送嚴格匹配的模型類:

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

Handling Validation Errors——處理驗證錯誤

 當驗證失敗時,Web API並不會自動地將錯誤返回給客戶端。這取決於控制器動作對模型狀態及響應進行適當的檢查。

你也可以創建一個動作過濾器,以便在控制器動作被調用之前,檢查模型的狀態。以下代碼演示了一個例子:

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

如果模型驗證失敗,此過濾器會返回一個含有驗證錯誤的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."
    ]
}

如果你正在使用CodePlex上最新版的Web API,可以使用HttpError類將驗證錯誤返回給客戶端。HttpError類在RC版(指Web API的預覽版)中無效。

你可以將此過濾器全局性地運用於所有Web API控制器。在Application_Start方法中,將此過濾器添加到HttpConfiguration.Filters集合:

protected void Application_Start()
{
    // ...

    GlobalConfiguration.Configuration.Filters.Add(new ModelValidationFilterAttribute());
}

另一種可選辦法是,通過將此過濾器作為注解屬性進行添加,你可以將它運用於個別控制器或控制器動作:

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM