WebApi 参数验证,参数绑定后进行验证
事件作用在Model绑定之后,action执行之前。有时候我们要检查model绑定的内容,比如是否为空,长度,大小,格式等等。
最简单的属性必选判定,需要在Model上面设定 [Required] 也可以设定异常说明的内容
http://localhost:20138/api/Demo

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,那么显示

同样还有验证字符串最大长度
[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);
}
}

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

[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

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
根据不同级别的人,判定工资应该在哪个范围之内

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

浙公网安备 33010602011771号