在ASP.NET Web API中处理ModelState验证
我想知道如何使用ASP.NET Web API实现模型验证。我有我的模型,像这样:在ASP.NET Web API中处理ModelState验证
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控制器:
public void Post(Enquiry enquiry)
{
enquiry.EnquiryDate = DateTime.Now;
context.DaybookEnquiries.Add(enquiry);
context.SaveChanges();
}
如何添加if(ModelState.IsValid)
然后处理错误消息向下传递给用户?
关注的分离,我会建议你使用行为过滤模型验证,所以你不需要关心太多怎么办确认在您的API控制器:
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请求添加一些关于他们自己的信息的网站。如果他们试图输入的信息无效 - 他们如何知道他们的保存操作是否成功?
执行此操作的最佳方法是使用良好的旧的HTTP状态码,如200 OK
等。这样,你的JavaScript就可以使用正确的回调(错误,成功等)正确处理失败。
下面是关于这种方法的更高级版本的一个很好的教程,用一个ActionFilter和jQuery:http://asp.net/web-api/videos/getting-started/custom-validation
这只是返回我的'enquiry'对象,它没有说哪些属性是无效的,但?所以如果我将'CustomerAccountNumber'留空,它应该说默认的验证消息(CusomterAccountNumber字段是必需的。) – CallumVass 2012-07-27 11:26:24
编辑我的答案。 – 2012-07-27 11:30:48
我明白了,那么这是处理模型验证的“正确”方式吗?似乎有点混乱给我.. – CallumVass 2012-07-27 11:34:01
也许不是你要找的,但也许是不错的人知道:
如果您使用的是.NET网络API 2你可以只需做下面的事情G:
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."
]
}
}
当我问这个问题Web API 1刚刚发布,它可能从那以后大量移动:) – CallumVass 2014-05-16 15:06:27
一定要将这些属性标记为可选,否则您将得到一个无用的通用“发生错误。”错误信息。 – bouke 2015-11-09 17:31:58
你也可以抛出异常,如记录在这里: http://blogs.msdn.com/b/youssefm/archive/2012/06/28/error-handling-in-asp-net-webapi.aspx
注意,要做到这一点文章提出什么,请记住,包括System.Net.Http
您可以使用属性从System.ComponentModel.DataAnnotations
命名空间来设置验证规则。详情请参阅Model Validation - By Mike Wasson。
另请参阅视频ASP.NET Web API, Part 5: Custom Validation - Jon Galloway
其他参考资料
- Take a Walk on the Client Side with WebAPI and WebForms
- How ASP.NET Web API binds HTTP messages to domain models, and how to work with media formats in Web API.
- Dominick Baier - Securing ASP.NET Web APIs
- Hooking AngularJS validation to ASP.NET Web API Validation
- Displaying ModelState Errors with AngularJS in ASP.NET MVC
- How to render errors to client? AngularJS/WebApi ModelState
- Dependency-Injected Validation in Web API
我不得不实施一个问题accepted solution pattern在我的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());
这里我的模型后,直接注册,您可以检查一个
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);
};
或者,如果您正在为您的应用程序错误的简单集合..这是我实现这一点:
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" ] }
这需要命名空间是'System.Net.Http','System.Net'' System.Web.Http.Controllers'和'System.Web.Http.Filters'。 – 2013-01-15 22:38:26
在官方的ASP.NET Web Api页面上也有类似的实现:http://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web -api – 2013-07-04 14:08:24
即使不把[ValidationActionFilter]放在web api上面,它仍然会调用代码并给我错误的请求。 – micronyks 2015-05-26 14:48:01