我想知道如何使用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; }
}
然后我的API控制器中有一个Post操作:
public void Post(Enquiry enquiry)
{
enquiry.EnquiryDate = DateTime.Now;
context.DaybookEnquiries.Add(enquiry);
context.SaveChanges();
}
如何添加if(ModelState.IsValid)
然后处理错误消息以传递给用户?
答案 0 :(得分:171)
为了分离关注点,我建议您使用动作过滤器进行模型验证,因此您不需要太在意如何在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);
}
}
}
答案 1 :(得分:27)
像这样,例如:
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请求添加一些自己的信息。如果他们试图输入的信息无效,他们将如何知道他们的保存行动是否成功该怎么办?
执行此操作的最佳方法是使用 Good Old HTTP Status Codes ,例如200 OK
,依此类推。这样,您的JavaScript可以使用正确的回调(错误,成功等)正确处理失败。
这是一个关于此方法的更高级版本的精彩教程,使用ActionFilter和jQuery:http://asp.net/web-api/videos/getting-started/custom-validation
答案 2 :(得分:23)
也许不是你想要的东西,但也许有人知道:
如果您使用的是.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."
]
}
}
答案 3 :(得分:9)
您可以使用System.ComponentModel.DataAnnotations
命名空间中的属性来设置验证规则。有关详细信息,请参阅Model Validation - By Mike Wasson。
另请参阅视频ASP.NET Web API, Part 5: Custom Validation - Jon Galloway
其他参考资料
答案 4 :(得分:6)
或者,如果您正在为您的应用寻找简单的错误集合..这是我的实现:
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" ] }
答案 5 :(得分:2)
在这里,您可以检查以逐一显示模型状态错误
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
}
}
}
答案 6 :(得分:2)
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);
};
答案 7 :(得分:2)
在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);
};
});
答案 8 :(得分:1)
您还可以抛出异常,如下所示: http://blogs.msdn.com/b/youssefm/archive/2012/06/28/error-handling-in-asp-net-webapi.aspx
注意,要执行该文章建议的内容,请记住包含System.Net.Http
答案 9 :(得分:1)
我在实施accepted solution pattern时出现问题,ModelStateFilter
对于某些模型对象,false
将始终返回actionContext.ModelState.IsValid
(以及随后为400){/ 1}}:
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());