在ASP.NET Web API中处理ModelStatevalidation

我想知道如何使用ASP.NET Web API实现模型validation。 我有我的模型是这样的:

public class Enquiry { [Key] public int EnquiryId { get; set; } [Required] public DateTime EnquiryDate { get; set; } [Required] public string CustomerAccountNumber { get; set; } [Required] public string ContactName { get; set; } } 

然后我在我的API控制器中有一个Post操作:

 public void Post(Enquiry enquiry) { enquiry.EnquiryDate = DateTime.Now; context.DaybookEnquiries.Add(enquiry); context.SaveChanges(); } 

如何添加if(ModelState.IsValid) ,然后处理错误消息传递给用户?

为了分离问题,我build议你使用动作filter进行模型validation,所以你不需要太在意如何在你的api控制器中进行validation:

 using System.Net; using System.Net.Http; using System.Web.Http.Controllers; using System.Web.Http.Filters; namespace System.Web.Http.Filters { public class ValidationActionFilter : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { var modelState = actionContext.ModelState; if (!modelState.IsValid) actionContext.Response = actionContext.Request .CreateErrorResponse(HttpStatusCode.BadRequest, modelState); } } } 

像这样,例如:

 public HttpResponseMessage Post(Person person) { if (ModelState.IsValid) { PersonDB.Add(person); return Request.CreateResponse(HttpStatusCode.Created, person); } else { // the code below should probably be refactored into a GetModelErrors // method on your BaseApiController or something like that var errors = new List<string>(); foreach (var state in ModelState) { foreach (var error in state.Value.Errors) { errors.Add(error.ErrorMessage); } } return Request.CreateResponse(HttpStatusCode.Forbidden, errors); } } 

这将返回这样的响应(假设JSON,但XML的基本原理相同):

 HTTP/1.1 400 Bad Request Content-Type: application/json; charset=utf-8 (some headers removed here) ["A value is required.","The field First is required.","Some custom errorm essage."] 

你当然可以用你喜欢的方式构造你的错误对象/列表,例如添加字段名称,字段ID等。

即使这是一个“单向”的Ajax调用,像一个新的实体的POST,你仍然应该返回一些东西给调用者 – 这表明请求是否成功。 设想一个网站,你的用户将通过AJAX POST请求添加一些关于自己的信息。 如果他们试图input的信息无效,他们将如何知道他们的“保存”操作是否成功?

要做到这一点的最佳方法是使用良好的旧的HTTP状态代码,200 OK等。 这样,你的JavaScript可以正确地使用正确的callback(错误,成功等)处理失败。

这里有一个关于这个方法更高级版本的好教程,使用ActionFilter和jQuery: http : //asp.net/web-api/videos/getting-started/custom-validation

也许不是你要找的东西,但也许对某个人来说很好:

如果您正在使用.net Web Api 2,则可以执行以下操作:

 if (!ModelState.IsValid) return BadRequest(ModelState); 

根据模型错误,你会得到这个结果:

 { Message: "The request is invalid." ModelState: { model.PropertyA: [ "The PropertyA field is required." ], model.PropertyB: [ "The PropertyB field is required." ] } } 

Followng来自模型validation – Mike Wasson

在ASP.NET Web API中,可以使用System.ComponentModel.DataAnnotations命名空间中的属性为模型上的属性设置validation规则。

validation失败时,Web API不会自动向客户端返回错误。 控制器的行为是检查模型状态并作出适当的响应。

您还可以创build一个操作筛选器,以在调用控制器操作之前检查模型状态。

如果模型validation失败,则此filter将返回一个包含validation错误的HTTP响应。

另请参阅videoASP.NET Web API,第5部分:自定义validation – Jon Galloway

其他参考

  1. 用WebAPI和WebForms在客户端散步
  2. ASP.NET Web API如何将HTTP消息绑定到域模型,以及如何在Web API中使用媒体格式。
  3. Dominick Baier – 保护ASP.NET Web API
  4. 将AngularJSvalidation连接到ASP.NET Web APIvalidation
  5. 在ASP.NET MVC中使用AngularJS显示模型状态错误
  6. 如何呈现错误到客户端? AngularJS / WebApi ModelState
  7. Web API中的dependency injectionvalidation

或者,如果你正在寻找简单的错误收集你的应用程序..这里是我的这个实现:

 public override void OnActionExecuting(HttpActionContext actionContext) { var modelState = actionContext.ModelState; if (!modelState.IsValid) { var errors = new List<string>(); foreach (var state in modelState) { foreach (var error in state.Value.Errors) { errors.Add(error.ErrorMessage); } } var response = new { errors = errors }; actionContext.Response = actionContext.Request .CreateResponse(HttpStatusCode.BadRequest, response, JsonMediaTypeFormatter.DefaultMediaType); } } 

错误消息响应如下所示:

 { "errors": [ "Please enter a valid phone number (7+ more digits)", "Please enter a valid e-mail address" ] } 

在这里您可以检查一个接一个地显示模型状态错误

  public HttpResponseMessage CertificateUpload(employeeModel emp) { if (!ModelState.IsValid) { string errordetails = ""; var errors = new List<string>(); foreach (var state in ModelState) { foreach (var error in state.Value.Errors) { string p = error.ErrorMessage; errordetails = errordetails + error.ErrorMessage; } } Dictionary<string, object> dict = new Dictionary<string, object>(); dict.Add("error", errordetails); return Request.CreateResponse(HttpStatusCode.BadRequest, dict); } else { //do something } } 

}

C#

  public class ValidateModelAttribute : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { if (actionContext.ModelState.IsValid == false) { actionContext.Response = actionContext.Request.CreateErrorResponse( HttpStatusCode.BadRequest, actionContext.ModelState); } } } 

  [ValidateModel] public HttpResponseMessage Post([FromBody]AnyModel model) { 

使用Javascript

 $.ajax({ type: "POST", url: "/api/xxxxx", async: 'false', contentType: "application/json; charset=utf-8", data: JSON.stringify(data), error: function (xhr, status, err) { if (xhr.status == 400) { DisplayModelStateErrors(xhr.responseJSON.ModelState); } }, .... function DisplayModelStateErrors(modelState) { var message = ""; var propStrings = Object.keys(modelState); $.each(propStrings, function (i, propString) { var propErrors = modelState[propString]; $.each(propErrors, function (j, propError) { message += propError; }); message += "\n"; }); alert(message); }; 

您也可以在此处loggingexception: http : //blogs.msdn.com/b/youssefm/archive/2012/06/28/error-handling-in-asp-net-webapi.aspx

请注意,要做文章build议,记得包括System.Net.Http

我有一个问题实现了接受的解决scheme模式 ,我的ModelStateFilter总是返回false (和随后400)的actionContext.ModelState.IsValid对于某些模型对象:

 public class ModelStateFilter : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { if (!actionContext.ModelState.IsValid) { actionContext.Response = new HttpResponseMessage { StatusCode = HttpStatusCode.BadRequest}; } } } 

我只接受JSON,所以我实现了一个自定义模型联编程序类:

 public class AddressModelBinder : System.Web.Http.ModelBinding.IModelBinder { public bool BindModel(HttpActionContext actionContext, System.Web.Http.ModelBinding.ModelBindingContext bindingContext) { var posted = actionContext.Request.Content.ReadAsStringAsync().Result; AddressDTO address = JsonConvert.DeserializeObject<AddressDTO>(posted); if (address != null) { // moar val here bindingContext.Model = address; return true; } return false; } } 

我通过模型后直接注册

 config.BindParameter(typeof(AddressDTO), new AddressModelBinder());