Correct way to disable model validation in ASP.Net Core 2 MVC

15,839

Solution 1

As of aspnet core 3.1, this is how you disable model validation as seen in docs:

First create this NullValidator class:

public class NullObjectModelValidator : IObjectModelValidator
{
    public void Validate(ActionContext actionContext,
        ValidationStateDictionary validationState, string prefix, object model)
    {

    }
}

Then use it in place of the real model validator:

services.AddSingleton<IObjectModelValidator, NullObjectModelValidator>();

Note that this only disable Model validation, you'll still get model binding errors.

Solution 2

 services.Configure<ApiBehaviorOptions>(options =>
        {
            options.SuppressModelStateInvalidFilter = true;
        });

should disable automatic model state validation.

Solution 3

Use this extension method:

public static IServiceCollection DisableDefaultModelValidation(this IServiceCollection services)
{
  ServiceDescriptor serviceDescriptor = services.FirstOrDefault<ServiceDescriptor>((Func<ServiceDescriptor, bool>) (s => s.ServiceType == typeof (IObjectModelValidator)));
  if (serviceDescriptor != null)
  {
    services.Remove(serviceDescriptor);
    services.Add(new ServiceDescriptor(typeof (IObjectModelValidator), (Func<IServiceProvider, object>) (_ => (object) new EmptyModelValidator()), ServiceLifetime.Singleton));
  }
  return services;
}


public class EmptyModelValidator : IObjectModelValidator
{
  public void Validate(ActionContext actionContext, ValidationStateDictionary validationState, string prefix, object model)
  {
  }
}

Ussage:

public void ConfigureServices(IServiceCollection services)
{
    services.DisableDefaultModelValidation();
}

Solution 4

You should consider to use the ValidateNeverAttribute, which is nearly undocumented and well hidden by Microsoft.

[ValidateNever]
public class Entity 
{
....
}

This gives you fine grained control over which entities to validate and which not.

Solution 5

Create empty model validator class.

public class EmptyModelValidator : IObjectModelValidator {
    public void Validate(
        ActionContext actionContext, 
        ValidationStateDictionary validationState,
        string prefix,
        object model) {
    }
}

Replace DefaultModelValidator with EmptyModelValidator in configure services method.

services.Replace(
    new ServiceDescriptor(typeof(IObjectModelValidator), 
    typeof(EmptyModelValidator),
    ServiceLifetime.Singleton)
);

EmptyModelValidator not validates model so ModelState.IsValid always return false.

Share:
15,839

Related videos on Youtube

S Waye
Author by

S Waye

Updated on October 13, 2022

Comments

  • S Waye
    S Waye over 1 year

    Set up MVC with the extension method

    services.AddMvc()
    

    Then in a controller, and this may apply to GET also, create a method for the POST action with a parameter supplied in the body, e.g.

    [HttpPost("save")]
    public Entity Save([FromBody]Entity someEntity)
    

    When the action is called the MVC pipeline will call the ParameterBinder which in turn calls DefaultObjectValidator. I don't want the validation (its slow for one thing, but more importantly is looping on complex cyclical graphs), but it seems the only way to turn off validation in the pipeline is something like this:

    public class NonValidatingValidator : IObjectModelValidator
    {
        public void Validate(ActionContext actionContext, ValidationStateDictionary validationState, string prefix, object model)
        {
        }
    }
    

    and in the StartUp/ConfigureServices:

            var validator = services.FirstOrDefault(s => s.ServiceType == typeof(IObjectModelValidator));
            if (validator != null)
            {
                services.Remove(validator);
                services.Add(new ServiceDescriptor(typeof(IObjectModelValidator), _ => new NonValidatingValidator(), ServiceLifetime.Singleton));
            }
    

    which seems like a sledgehammer. I've looked around and can't find an alternative, also tried to remove the DataAnnotationModelValidator without success, so would like to know if there's a better/correct way to turn off validation?

    • thejman
      thejman over 6 years
      I think your solution is good. You can simplify the dependency registration with just: services.AddSingleton<IObjectModelValidator>(new NonValidatingValidator());
  • S Waye
    S Waye over 6 years
    Same unfortunately, this is part of the stack:` Microsoft.AspNetCore.Mvc.Core.dll!Microsoft.AspNetCore.Mvc.‌​Internal.DefaultObje‌​ctValidator.Validate‌​(Microsoft.AspNetCor‌​e.Mvc.ActionContext actionContext, Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationS‌​tateDictionary validationState, string prefix, object model) Unknown Non-user code. Skipped loading symbols. Microsoft.AspNetCore.Mvc.Core.dll!Microsoft.AspNetCore.Mvc.‌​ModelBinding.Paramet‌​erBinder.BindModelAs‌​ync(Microsoft.AspNet‌​Core.Mvc.ActionConte‌​xt actionContext, Microsoft.AspNetCore.Mvc.ModelBinding.IModelBinder modelBinder`
  • ypsilo0n
    ypsilo0n over 6 years
    Same what? You are getting an exception now?
  • S Waye
    S Waye over 6 years
    No, I mean its still calling the DefaultObjectValidator, I suppose there exists some code along the lines of "do we have a validator, if not add DefaultObjectValidator)
  • Kamran Shahid
    Kamran Shahid over 4 years
    is this still valid for asp.net core 3.1? also is there any other thing which i can disable to improve my api response?
  • disklosr
    disklosr about 4 years
    This answer is wrong. It only disables the handler of validation errors but doesn't disable validation itself!
  • S Waye
    S Waye over 3 years
    I dont think this really adds significantly more than @thejman 's comment in the question, but will accept as the answer to close things out. Thanks!
  • bramve
    bramve about 3 years
    There is a big gotcha with this solution which you should be wary of (And cost me a lot of time to find out): When you use both this solution + the [ApiController] attribute [FromHeader] parameters in controllers will always automatically give a 400 bad request without any logging making it hard to find the source of the problem.
  • Nico
    Nico over 2 years
    Its name is quite tricky. I guess the filter just handles the returned result in case of validation failure. It doesn't stop the validation from happening in the first place.
  • David Keaveny
    David Keaveny over 2 years
    This approach might be useful for a few specific classes, but if you want to disable application-wide, I wouldn't want to have to decorate all my classes (and remember to add this to future classes). Much better to do it at the middleware level and have done with it.
  • ahdung
    ahdung about 2 years
    @disklosr How about services.AddControllers(options => options.ModelValidatorProviders.Clear());