zoukankan      html  css  js  c++  java
  • [水煮 ASP.NET Web API2 方法论](1-6)Model Validation

    问题

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



  • 相关阅读:
    WGS84经纬度坐标与web墨卡托之间的转换【转】
    ArcGIS API for Javascript配置
    百度地图BMap API实例
    VS2010 Web项目需要缺少的Web组件才能加载
    单态模式
    对服务的操作
    根据子级ID获取其所有父级
    在DropDownList里显示多级分类
    jQuery给CheckBox添加事件
    FolderBrowserDialog使用
  • 原文地址:https://www.cnblogs.com/shuizhucode/p/6064260.html
Copyright © 2011-2022 走看看