ModelState.IsValid甚至当它不应该?

我有我需要validation我的用户模型的API。 我select一种方法,为创build/编辑操作创build不同的类,以避免批量分配,并将validation和实际模型分开。

我不知道为什么,但ModelState.IsValid即使不应该返回true。 难道我做错了什么?

调节器

 public HttpResponseMessage Post(UserCreate user) { if (ModelState.IsValid) // It's valid even when user = null { var newUser = new User { Username = user.Username, Password = user.Password, Name = user.Name }; _db.Users.Add(newUser); _db.SaveChanges(); return Request.CreateResponse(HttpStatusCode.Created, new { newUser.Id, newUser.Username, newUser.Name }); } return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState); } 

模型

 public class UserCreate { [Required] public string Username { get; set; } [Required] public string Password { get; set; } [Required] public string Name { get; set; } } 

debuggingcertificate

证明

ModelState.IsValid内部检查Values.All(modelState => modelState.Errors.Count == 0)expression式。

因为没有input,所以Values集合将是空的,所以ModelState.IsValid将为true

所以你需要明确地处理这种情况:

 if (user != null && ModelState.IsValid) { } 

无论这是一个好还是坏的devise决定,如果你没有validation它将是真实的是一个不同的问题…

这里是一个动作filter来检查空模型或无效模型。 (所以你不必写每个动作的检查)

 using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http.Controllers; using System.Web.Http.Filters; namespace Studio.Lms.TrackingServices.Filters { public class ValidateViewModelAttribute : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { if (actionContext.ActionArguments.Any(kv => kv.Value == null)) { actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Arguments cannot be null"); } if (actionContext.ModelState.IsValid == false) { actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState); } } } } 

您可以在全球注册

 config.Filters.Add(new ValidateViewModelAttribute()); 

或者根据课堂/行动的需求使用它

  [ValidateViewModel] public class UsersController : ApiController { ... 

我写了一个自定义filter,它不仅确保所有非可选对象属性都被传递,而且还检查模型状态是否有效:

 [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public sealed class ValidateModelAttribute : ActionFilterAttribute { private static readonly ConcurrentDictionary<HttpActionDescriptor, IList<string>> NotNullParameterNames = new ConcurrentDictionary<HttpActionDescriptor, IList<string>> (); /// <summary> /// Occurs before the action method is invoked. /// </summary> /// <param name="actionContext">The action context.</param> public override void OnActionExecuting (HttpActionContext actionContext) { var not_null_parameter_names = GetNotNullParameterNames (actionContext); foreach (var not_null_parameter_name in not_null_parameter_names) { object value; if (!actionContext.ActionArguments.TryGetValue (not_null_parameter_name, out value) || value == null) actionContext.ModelState.AddModelError (not_null_parameter_name, "Parameter \"" + not_null_parameter_name + "\" was not specified."); } if (actionContext.ModelState.IsValid == false) actionContext.Response = actionContext.Request.CreateErrorResponse (HttpStatusCode.BadRequest, actionContext.ModelState); } private static IList<string> GetNotNullParameterNames (HttpActionContext actionContext) { var result = NotNullParameterNames.GetOrAdd (actionContext.ActionDescriptor, descriptor => descriptor.GetParameters () .Where (p => !p.IsOptional && p.DefaultValue == null && !p.ParameterType.IsValueType && p.ParameterType != typeof (string)) .Select (p => p.ParameterName) .ToList ()); return result; } } 

我把它放在所有Web API操作的全局filter中:

 config.Filters.Add (new ValidateModelAttribute ()); 

为asp.net核心稍微更新…

 [AttributeUsage(AttributeTargets.Method)] public sealed class CheckRequiredModelAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext context) { var requiredParameters = context.ActionDescriptor.Parameters.Where( p => ((ControllerParameterDescriptor)p).ParameterInfo.GetCustomAttribute<RequiredModelAttribute>() != null).Select(p => p.Name); foreach (var argument in context.ActionArguments.Where(a => requiredParameters.Contains(a.Key, StringComparer.Ordinal))) { if (argument.Value == null) { context.ModelState.AddModelError(argument.Key, $"The argument '{argument.Key}' cannot be null."); } } if (!context.ModelState.IsValid) { var errors = context.ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage); context.Result = new BadRequestObjectResult(errors); return; } base.OnActionExecuting(context); } } [AttributeUsage(AttributeTargets.Parameter)] public sealed class RequiredModelAttribute : Attribute { } services.AddMvc(options => { options.Filters.Add(typeof(CheckRequiredModelAttribute)); }); public async Task<IActionResult> CreateAsync([FromBody][RequiredModel]RequestModel request, CancellationToken cancellationToken) { //... } 

这发生在我身上,在我的情况下,我不得不改变using Microsoft.Build.Framework; using System.ComponentModel.DataAnnotations; (并添加参考)。

这个问题发生在我身上。我不知道为什么,但只要改变你的行动对象名称(UserCreate用户)通过其他一些像(UserCreate User_create)