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

Viewed 20801

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?

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

should disable automatic model state validation.

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.

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();
}

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.

The .AddMvc() extension method has an overload where you can configure a lot of things. One of these things is the list of ModelValidatorProviders.

If you clear this list, e.g.:

services.AddMvc(options => options.ModelValidatorProviders.Clear());

validation should not take place any longer.

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.

To turn off validation for everything inheriting a class:

  var mvc = services.AddMvc(options =>
  {
    options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(VMClass))); 
  }); // to avoid validation of the complete world by following VMClass refs
Related