C# ModelState 对空模型有效
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19851352/
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
ModelState is valid with null model
提问by nVentimiglia
I have a Model object with a required attribute
我有一个具有必需属性的模型对象
public class ApiPing
{
[Required]
public DateTime ClientTime { get; set; }
public DateTime ServerTime { get; set; }
}
I have a Controller method that checks model state.
我有一个检查模型状态的控制器方法。
public IHttpActionResult Ping(ApiPing model)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
model.ServerTime = DateTime.UtcNow;
return Ok(model);
}
If I submit a submit a proper request (with a model) to the action method I get an correct value from ModeState.IsValid (true). However, when I submit an invalid request (without a model, so the model is null) I get an erroneous ModelState.IsValid (also true).
如果我向 action 方法提交一个正确的请求(带有模型),我会从 ModeState.IsValid (true) 获得正确的值。但是,当我提交无效请求(没有模型,所以模型为空)时,我得到一个错误的 ModelState.IsValid(也是如此)。
I could simply check if the model is null in my code, but that smells. Is this an intended 'feature' or a bug in ModelState validation? Am I doing something wrong ? Am I expecting too much ?
我可以简单地检查我的代码中的模型是否为空,但这很糟糕。这是 ModelState 验证中的预期“功能”还是错误?难道我做错了什么 ?是我期待太多了吗?
采纳答案by julianox
I had the same problem before and the answer is already available in a few forums and even here at SO: ModelState.IsValid even when it should not be?
我以前遇到过同样的问题,答案已经在几个论坛中可用,甚至在 SO:ModelState.IsValid 即使不应该出现?
You can also add a custom filter to validate (invalidate) missing fields and/or null values http://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api
您还可以添加自定义过滤器来验证(无效)缺失的字段和/或空值 http://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet -web-api
回答by Jose Ch.
Here is an action filter to check for null models or invalid models.
这是一个用于检查空模型或无效模型的操作过滤器。
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);
}
}
}
}
You can register it globally:
您可以全局注册它:
config.Filters.Add(new ValidateViewModelAttribute());
Or use it on demand on classes/actions
或者在类/操作上按需使用它
[ValidateViewModel]
public class UsersController : ApiController
{ ...
回答by Oleg Sakharov
- Declare your model as a struct
- Change type of all your required properties to be nullable
- 将模型声明为结构
- 将所有必需属性的类型更改为可为空
回答by Roberto B
I have found the hint for this problem here. So i will give my solution here.
我在这里找到了这个问题的提示。所以我会在这里给出我的解决方案。
How do you use my solution? You can register it globally:
你如何使用我的解决方案?您可以全局注册它:
config.Filters.Add(new ValidateModelStateAttribute());
Or use it on demand for a class
或者在课堂上按需使用
[ValidateModelState]
public class UsersController : ApiController
{...
or for a methode
或方法
[ValidateModelState]
public IHttpActionResult Create([Required] UserModel data)
{...
As you can see, a [System.ComponentModel.DataAnnotations.Required]
atribute has been placed in the method parameter.
This indicates that the model is required and can not be null
.
如您所见,[System.ComponentModel.DataAnnotations.Required]
在方法参数中放置了一个属性。这表明模型是必需的,不能是null
。
You can also use with a custom message:
您还可以使用自定义消息:
[ValidateModelState]
public IHttpActionResult Create([Required(ErrorMessage = "Custom message")] UserModel data)
{...
Here is my code:
这是我的代码:
using System;
using System.Collections.Concurrent;
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace your_base_namespace.Web.Http.Filters
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true)]
public class ValidateModelStateAttribute : ActionFilterAttribute
{
private delegate void ValidateHandler(HttpActionContext actionContext);
private static readonly ConcurrentDictionary<HttpActionBinding, ValidateHandler> _validateActionByActionBinding;
static ValidateModelStateAttribute()
{
_validateActionByActionBinding = new ConcurrentDictionary<HttpActionBinding, ValidateHandler>();
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
GetValidateHandler(actionContext.ActionDescriptor.ActionBinding)(actionContext);
if (actionContext.ModelState.IsValid)
return;
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
}
private ValidateHandler GetValidateHandler(HttpActionBinding actionBinding)
{
ValidateHandler validateAction;
if (!_validateActionByActionBinding.TryGetValue(actionBinding, out validateAction))
_validateActionByActionBinding.TryAdd(actionBinding, validateAction = CreateValidateHandler(actionBinding));
return validateAction;
}
private ValidateHandler CreateValidateHandler(HttpActionBinding actionBinding)
{
ValidateHandler handler = new ValidateHandler(c => { });
var parameters = actionBinding.ParameterBindings;
for (int i = 0; i < parameters.Length; i++)
{
var parameterDescriptor = (ReflectedHttpParameterDescriptor)parameters[i].Descriptor;
var attribute = parameterDescriptor.ParameterInfo.GetCustomAttribute<RequiredAttribute>(true);
if (attribute != null)
handler += CreateValidateHandler(attribute, parameterDescriptor.ParameterName);
}
return handler;
}
private static ValidateHandler CreateValidateHandler(ValidationAttribute attribute, string name)
{
return CreateValidateHandler(attribute, new ValidationContext(new object()) { MemberName = name });
}
private static ValidateHandler CreateValidateHandler(ValidationAttribute attribute, ValidationContext context)
{
return new ValidateHandler(actionContext =>
{
object value;
actionContext.ActionArguments.TryGetValue(context.MemberName, out value);
var validationResult = attribute.GetValidationResult(value, context);
if (validationResult != null)
actionContext.ModelState.AddModelError(context.MemberName, validationResult.ErrorMessage);
});
}
}
}