在WebApi2中使用模型验证

时间:2020-12-24 13:30:37

很多时候我们在接收到客户端提交过来的请求之前,要验证一下数据合法性再执行操作。

 

数据注解Data Annotations

    WepApi中可以使用System.ComponentModel.DataAnnotations命名空间的属性,在你的model类中设置属性,来实现验证。

考虑以下场景:

using System.ComponentModel.DataAnnotations;

namespace MyApi.Models
{
    
public class Product
    {
        
public int Id { getset; }
        [
Required]
        
public string Name { getset; }
        
public decimal Price {getset;}
        [
Range(0999)]
        
public double Weight { getset; }
    }
}

    如果你在MVC中使用过模型验证,那么看起来很眼熟,[Required]特性表示Name不能为null[Range]特性表示Weight必须在0-999范围内。

    假设收到客户端POST过来的json数据:

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

    我们可以看到数据并没有包含Name,而Name我们是标记了[Required]特性的。当WebApi将其转换为Product实体的时候,就会发生验证冲突。

    在你的Action中可以验证Model是否合法:

         public class ProductsController : ApiController
    {
        
public HttpResponseMessagePost(Product product)
        {
            
if (ModelState.IsValid)
            {
                
// Dosomething with the product (not shown).

                                      returnnew HttpResponseMessage(HttpStatusCode.OK);
            }
            
else
            {
                
return Request.CreateErrorResponse(HttpStatusCode.BadRequestModelState);
            }
        }
    }

 

   但是模型验证不能保证完全不会出现问题,所以你需要在程序的其他层中增加验证,比如在Model层增加外键关联等等(EF)。

如果你使用的是EF可以参照文章Using Web API withEntity Framework,其中介绍了很多类似的问题。

 

Under-Posting”(参数缺失)

    传过来的数据中参数缺失的情况,例如:

   

   {"Id":4"Name":"Gizmo"这里没有传PirceWeight参数,此时Json Formatter会指定默认的值;

 

"Over-Posting"(参数多余)

    传过来的参数多

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

 

    可以看到传过来一个不存在Color属性,既然这样,formatter会忽略该值,XMLformatter也一样。

 

 

注意,当你打算将某个属性作为只读属性的时候可能有问题。

     例如

public class UserProfile
{
    
public string Name { getset; }
    
public UriBlog { getset; }
    
public bool IsAdmin { getset;}  // uh-oh!
}

     你不希望用户可以修改IsAdmin这个值,因为这样会篡改为管理员权限!

     最好的办法就是使用DTO对象,说白了就是封装一层面向展示层的对象,将IsAdmin剔除,这样用户就不会修改该值了。

public class UserProfileDTO
{
    
public string Name { getset; }
    
public UriBlog { getset; }
    
// Leave out "IsAdmin"
}

 

 

 处理验证错误

 

   1.当验证错误的时候WebApi不会自动向客户端返回错误,而是有Action编写代码实现向客户端返回错误。

 

   2.你也可以自己创建一个action filter去验证模型状态(model state),如果发生错误则会想客户端返回错误信息,action也不会执行。

namespace MyApi.Filters
{
    
public class ValidateModelAttributeActionFilterAttribute
    {
        
public override void OnActionExecuting(HttpActionContext actionContext)
        {
            
if (actionContext.ModelState.IsValid == false)
            {
                actionContext.
Response = actionContext.Request.CreateErrorResponse(
                    
HttpStatusCode.BadRequest,actionContext.ModelState);
            }
        }
    }
}

 

HTTP/1.1 400 Bad Request

Content-Type: application/json; charset=utf-8

Date: Tue, 16 Jul 2013 21:02:29 GMT

Content-Length: 331

{

  "Message": "The request isinvalid.",

  "ModelState": {

    "product": [

      "Required property'Name' not found in JSON. Path '', line 1, position 17."

    ],

    "product.Name": [

      "The Name field isrequired."

    ],

    "product.Weight": [

      "The field Weight mustbe between 0 and 999."

    ]

  }

}

 

如何应用这个filter呢?需要在 HttpConfiguration.Filters 集合中添加刚才创建的filter

public static class WebApiConfig
    {
        
public static void Register(HttpConfiguration config)
        {
            config.
Filters.Add(new ValidateModelAttribute());
        }
}

 

3.另外一个方式就是添加特性(简便省事儿)

public class ProductsController : ApiController
{
    [
ValidateModel]
    
public HttpResponseMessagePost(Product product)
    {
        
// ...
    }
}