C# 在 ASP.NET Web API 中处理 ModelState 验证
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11686690/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Handle ModelState Validation in ASP.NET Web API
提问by CallumVass
I was wondering how I can achieve model validation with ASP.NET Web API. I have my model like so:
我想知道如何使用 ASP.NET Web API 实现模型验证。我有这样的模型:
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; }
}
I then have a Post action in my API Controller:
然后我在我的 API 控制器中有一个 Post 操作:
public void Post(Enquiry enquiry)
{
enquiry.EnquiryDate = DateTime.Now;
context.DaybookEnquiries.Add(enquiry);
context.SaveChanges();
}
How do I add if(ModelState.IsValid)and then handle the error message to pass down to the user?
如何添加if(ModelState.IsValid)然后处理错误消息以传递给用户?
采纳答案by cuongle
For separation of concern, I would suggest you use action filter for model validation, so you don't need to care much how to do validation in your api controller:
对于关注点分离,我建议您使用动作过滤器进行模型验证,因此您无需太在意如何在 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);
}
}
}
回答by Anders Arpi
Like this, for example:
像这样,例如:
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);
}
}
This will return a response like this (assuming JSON, but same basic principle for XML):
这将返回这样的响应(假设为 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."]
You can of course construct your error object/list any way you like, for example adding field names, field id's etc.
您当然可以以任何您喜欢的方式构建您的错误对象/列表,例如添加字段名称、字段 ID 等。
Even if it's a "one way" Ajax call like a POST of a new entity, you should still return something to the caller - something that indicates whether or not the request was successful. Imagine a site where your user will add some info about themselves via an AJAX POST request. What if the information they have tried to entered isn't valid - how will they know if their Save action was successful or not?
即使它是一个“单向”的 Ajax 调用,比如一个新实体的 POST,你仍然应该向调用者返回一些东西——指示请求是否成功的东西。想象一个站点,您的用户将通过 AJAX POST 请求添加一些关于他们自己的信息。如果他们尝试输入的信息无效怎么办 - 他们如何知道他们的保存操作是否成功?
The best way to do this is using Good Old HTTP Status Codeslike 200 OKand so on. That way your JavaScript can properly handle failures using the correct callbacks (error, success etc).
最好的方法是使用Good Old HTTP Status Codes 之类的200 OK。这样你的 JavaScript 就可以使用正确的回调(错误、成功等)正确处理失败。
Here's a nice tutorial on a more advanced version of this method, using an ActionFilter and jQuery: http://asp.net/web-api/videos/getting-started/custom-validation
这是使用 ActionFilter 和 jQuery 的有关此方法的更高级版本的不错的教程:http: //asp.net/web-api/videos/getting-started/custom-validation
回答by Are Almaas
Maybe not what you were looking for, but perhaps nice for someone to know:
也许不是你要找的,但也许很高兴有人知道:
If you are using .net Web Api 2 you could just do the following:
如果您使用的是 .net Web Api 2,您可以执行以下操作:
if (!ModelState.IsValid)
return BadRequest(ModelState);
Depending on the model errors, you get this result:
根据模型错误,您会得到以下结果:
{
Message: "The request is invalid."
ModelState: {
model.PropertyA: [
"The PropertyA field is required."
],
model.PropertyB: [
"The PropertyB field is required."
]
}
}
回答by Christopher Davies
You can also throw exceptions as documented here: http://blogs.msdn.com/b/youssefm/archive/2012/06/28/error-handling-in-asp-net-webapi.aspx
您还可以按照此处记录的方式抛出异常:http: //blogs.msdn.com/b/youssefm/archive/2012/06/28/error-handling-in-asp-net-webapi.aspx
Note, to do what that article suggests, remember to include System.Net.Http
请注意,要执行该文章建议的操作,请记住包含 System.Net.Http
回答by LCJ
You can use attributes from the System.ComponentModel.DataAnnotationsnamespace to set validation rules. Refer Model Validation - By Mike Wassonfor details.
您可以使用System.ComponentModel.DataAnnotations命名空间中的属性来设置验证规则。有关详细信息,请参阅模型验证 - Mike Wasson。
Also refer video ASP.NET Web API, Part 5: Custom Validation - Jon Galloway
另请参阅视频ASP.NET Web API,第 5 部分:自定义验证 - Jon Galloway
Other References
其他参考
- 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
回答by user326608
I had an issue implementing the accepted solution patternwhere my ModelStateFilterwould always return false(and subsequently a 400) for actionContext.ModelState.IsValidfor certain model objects:
我在实现公认的解决方案模式时遇到了问题,对于某些模型对象,我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};
}
}
}
I only accept JSON, so I implemented a custom model binder class:
我只接受 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;
}
}
Which I register directly after my model via
我直接在我的模型之后注册
config.BindParameter(typeof(AddressDTO), new AddressModelBinder());
回答by Debendra Dash
Here you can check to show the model state error one by one
这里可以一一检查显示模型状态错误
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
}
}
}
}
回答by Nick Hermans
C#
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
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);
};
回答by sandeep talabathula
Or, if you are looking for simple collection of errors for your apps.. here is my implementation of this:
或者,如果您正在为您的应用程序寻找简单的错误集合......这是我的实现:
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);
}
}
Error Message Response will look like:
错误消息响应将如下所示:
{ "errors": [ "Please enter a valid phone number (7+ more digits)", "Please enter a valid e-mail address" ] }
{ "errors": [ "Please enter a valid phone number (7+ more digits)", "Please enter a valid e-mail address" ] }
回答by MayankGaur
Add below code in startup.cs file
在 startup.cs 文件中添加以下代码
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2).ConfigureApiBehaviorOptions(options =>
{
options.InvalidModelStateResponseFactory = (context) =>
{
var errors = context.ModelState.Values.SelectMany(x => x.Errors.Select(p => new ErrorModel()
{
ErrorCode = ((int)HttpStatusCode.BadRequest).ToString(CultureInfo.CurrentCulture),
ErrorMessage = p.ErrorMessage,
ServerErrorMessage = string.Empty
})).ToList();
var result = new BaseResponse
{
Error = errors,
ResponseCode = (int)HttpStatusCode.BadRequest,
ResponseMessage = ResponseMessageConstants.VALIDATIONFAIL,
};
return new BadRequestObjectResult(result);
};
});

