WebApi 参数验证,参数绑定后进行验证

事件作用在Model绑定之后,action执行之前。有时候我们要检查model绑定的内容,比如是否为空,长度,大小,格式等等。

最简单的属性必选判定,需要在Model上面设定 [Required]  也可以设定异常说明的内容

http://localhost:20138/api/Demo

WebApi 参数验证,参数绑定后进行验证

 

 

 

public class Person
    {
        [Required(ErrorMessage ="Name属性必填")]
        public string Name { get; set; }
    }
        public HttpResponseMessage Get([FromUri]Person person)
        {
            if (ModelState.IsValid)
            {
                return this.Request.CreateResponse(HttpStatusCode.OK);
            }
            else
            {
                return this.Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
        }

  

或许有人会好奇,  页面显示的和属性设定的不同。这是因为还没到进一步那证那一步

如果URL是http://localhost:20138/api/Demo?Name,那么显示

WebApi 参数验证,参数绑定后进行验证

 

 

 同样还有验证字符串最大长度

[StringLength(50)]
常用的还有 数字范围 [Range(18, 25],指定字符串格式 正则 [RegularExpression("^[1]+[3,4,5,7,8]+\\d{9}"]

使用异常提示模板进行提示,后面要修改的时候还可以不用修改代码,定义在资源文件中,使用占位符
先设定有占位符的资源,其次需要在类属性上设定
public class Person
    {
        [Required(ErrorMessage ="Name属性必填")]
        public string Name { get; set; }

        [Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Resources))]
        [Range(18, 25, ErrorMessageResourceName = "Range", ErrorMessageResourceType = typeof(Resources))]
        public int? Age { get; set; }
    }
        public HttpResponseMessage Get([FromUri]Person person)
        {
            if (ModelState.IsValid)
            {
                return this.Request.CreateResponse(HttpStatusCode.OK);
            }
            else
            {
                return this.Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
        }

  

  

WebApi 参数验证,参数绑定后进行验证

 

 

 

http://localhost:20138/api/Demo?Name=12345678901&age=55

WebApi 参数验证,参数绑定后进行验证

 

[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Resources))]
        [Range(18, 25, ErrorMessageResourceName = "Range", ErrorMessageResourceType = typeof(Resources))]
        public int? Age { get; set; }

  

 我们还可以自定义参数验证规则,比如验证 属性必须是某几个固定的值之一,比如设定性别

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    public class DomainAttribute : ValidationAttribute
    {
        public IEnumerable<string> Values { get; private set; }

        public DomainAttribute(string value)
        {
            this.Values = new string[] { value };
        }

        public DomainAttribute(params string[] values)
        {
            this.Values = values;
        }

        public override bool IsValid(object value)// 验证是否有效value是传递的值
        {
            return this.Values.Any(item => value.ToString() == item);
        }

        public override string FormatErrorMessage(string name)// name 是栏位名称,验证失败走这一段
        {
            string[] values = this.Values.Select(value => string.Format("'{0}'", value)).ToArray();
            return string.Format(base.ErrorMessageString, name,string.Join(",", values));
        }
    }

 http://localhost:20138/api/Demo?Name=12345678901&age=22&Gender=Z

WebApi 参数验证,参数绑定后进行验证

public class Person
    {

        [Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Resources))]
        [Domain("M", "F", "m", "f", ErrorMessageResourceName = "Domain", ErrorMessageResourceType = typeof(Resources))]
        public string Gender { get; set; }


    }

  

 同时我们可以验证 同一个类,不同属性之间的比较,

 http://localhost:20138/api/Demo?Name=Jerry&Grade=G7&Salary=5000

 根据不同级别的人,判定工资应该在哪个范围之内

WebApi 参数验证,参数绑定后进行验证

 

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WebApi
{
    public class Employee
    {
        public string Name { get; set; }
        public string Grade { get; set; }

        [RangeIf("Grade", "G7", 2000, 3000)]
        [RangeIf("Grade", "G8", 3000, 4000)]
        [RangeIf("Grade", "G9", 4000, 5000)]
        public decimal Salary { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace WebApi
{
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]  // AlloMultiple=true  一个属性上可以加多个相同属性
    public class RangeIfAttribute : RangeAttribute  //继承 数字范围的内
    {
        public string Property { get; set; }
        public string Value { get; set; }

        public RangeIfAttribute(string property, string value, double minimum,double maximum) // 第一个值property,是 获取需要比较的其他属性的名称,这里指Grade
            : base(minimum, maximum)
        {
            this.Property = property;
            this.Value = value ?? "";
        }
  
        protected override ValidationResult IsValid(object value, ValidationContext validationContext) // Value 是通过URL获取的值 5000,
        {
            PropertyInfo property = validationContext.ObjectType.GetProperty(this.Property); // Property 是参数验证通过构造函数传进来的Grade 等级
            object propertyValue = property.GetValue(validationContext.ObjectInstance, null);
            propertyValue = propertyValue ?? "";
            if (propertyValue.ToString() != this.Value)  //构造函数传进来的等级与 参数属性验证的等级比较,不一样的PASS。一样的则进行比较,通过URL传进来的5000,等级G7,与 参数验证相同等级G7对应的2000, 3000进行比较
            {
                return ValidationResult.Success;
            }
            return base.IsValid(value, validationContext);
        }

        private object typeid;
        public override object TypeId
        {
            get { return typeid ?? (typeid = new object()); }
        }
    }
}

  

  

 通过过滤器优化参数验证

每次我们都要在action内验证 Model绑定后  ModelState.IsValid  是否false,比较麻烦,我们可以定义filter,在model绑定后,action开始前进行判断
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.Net.Http;

namespace WebApi
{
    public class ValidateAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            if (!actionContext.ModelState.IsValid)
            {
                actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
            }
            base.OnActionExecuting(actionContext);
        }
    }
}

在controller 上面修饰 过滤器,同时 action的返回值可以有 HttpResponseMessage  改为 void,意思一样

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using WebApi.Models;

namespace WebApi.Controllers
{
    [Validate]
    public class DemoController : ApiController
    {
        public void Get([FromUri]Employee employee) { }
    }
}

  

 

参数验证还有一种自绑定方式,在类里面进行参数验证

  

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using WebApi.Properties;

namespace WebApi.Models
{
    public class Person : IValidatableObject
    {
        public string Name { get; set; }
        public string Gender { get; set; }
        public int? Age { get; set; }

        public IEnumerable<ValidationResult> Validate(
            ValidationContext validationContext)
        {
            Person person = validationContext.ObjectInstance as Person;
            if (null == person)
            {
                yield break;
            }
            if (string.IsNullOrEmpty(person.Name))
            {
                yield return new ValidationResult("'Name'是必需字段",new string[] { "Name" });
            }

            if (string.IsNullOrEmpty(person.Gender))
            {
                yield return new ValidationResult("'Gender'是必需字段",new string[] { "Gender" });
            }
            else if (!new string[] { "M", "F" }.Any(g => string.Compare(person.Gender, g, true) == 0))
            {
                yield return new ValidationResult("有效'Gender'必须是'M','F'之一",
                    new string[] { "Gender" });
            }

            if (null == person.Age)
            {
                yield return new ValidationResult("'Age'是必需字段",new string[] { "Age" });
            }
            else if (person.Age > 25 || person.Age < 18)
            {
                yield return new ValidationResult("有效'Age'必须在18到25周岁之间",new string[] { "Age" });
            }
        }
    }
}

  




上一篇:windows平台的分布式微服务解决方案(5)--Web服务/WebApi的负载均衡


下一篇:WebApi 重定向 Redirect