ModelState is valid with null model

前端 未结 4 1513
刺人心
刺人心 2020-12-03 02:15

I have a Model object with a required attribute

public class ApiPing
{
    [Required]
    public DateTime ClientTime { get; set; }

    public DateTime Server         


        
相关标签:
4条回答
  • 2020-12-03 02:55

    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
     { ...
    
    0 讨论(0)
  • 2020-12-03 03:00

    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?

    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.strathweb.com/2012/10/clean-up-your-web-api-controllers-with-model-validation-and-null-check-filters/

    0 讨论(0)
  • 2020-12-03 03:15
    1. Declare your model as a struct
    2. Change type of all your required properties to be nullable
    0 讨论(0)
  • 2020-12-03 03:16

    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.

    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);
                });
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题