32

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?

2
  • 3
    I think your solution is good. You can simplify the dependency registration with just: services.AddSingleton<IObjectModelValidator>(new NonValidatingValidator()); Commented Nov 14, 2017 at 2:18
  • @thejman This is the correct answer Commented Aug 19, 2018 at 10:18

9 Answers 9

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

should disable automatic model state validation.

Sign up to request clarification or add additional context in comments.

7 Comments

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?
This answer is wrong. It only disables the handler of validation errors but doesn't disable validation itself!
@disklosr How about services.AddControllers(options => options.ModelValidatorProviders.Clear());
on .Net 7 working well, after this configuration we can easily do validation in Controller method like ModelState.IsValid then we can respond to user with custom validation model. Using this method will retriew all errors ModelState.Values.SelectMany(f => f.Errors).Select(f => f.ErrorMessage)
Don't know why this has any upvotes at all, this is totally wrong. As others have pointed out this does not actually disable model validation at all, it just doesn't return the auto-generated 400 error. Tested on .Net 6.
|
12

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.

2 Comments

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.
Also unfortuantely does not seem to work on single parameter level.
8

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.

2 Comments

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!
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.
7

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.

4 Comments

Same unfortunately, this is part of the stack:` Microsoft.AspNetCore.Mvc.Core.dll!Microsoft.AspNetCore.Mvc.Internal.DefaultObjectValidator.Validate(Microsoft.AspNetCore.Mvc.ActionContext actionContext, Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationStateDictionary validationState, string prefix, object model) Unknown Non-user code. Skipped loading symbols. Microsoft.AspNetCore.Mvc.Core.dll!Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(Microsoft.AspNetCore.Mvc.ActionContext actionContext, Microsoft.AspNetCore.Mvc.ModelBinding.IModelBinder modelBinder`
Same what? You are getting an exception now?
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)
Rather than DefaultObjectValidator I'm seeing ObjectModelValidator on the stack (Microsoft.AspNetCore.Mvc.Core.dll!Microsoft.AspNetCore.Mvc.ModelBinding. ObjectModelValidator.Validate), but yes, neither ModelValidatorProviders.Clear() nor SuppressModelStateInvalidFilter = true prevents validation. The latter avoids blocking your APIs from being called, but I still noticed that validation was happening when it triggered an exception in my own code, just as @SWaye noticed the performance impact.
5

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

Comments

4

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

1 Comment

I tried typeof(ControllerBase) as the type, but it didn't work. Then I realized that this needs to be the type of an incoming deserialized object (or perhaps the declared type of an API's parameter), not the type of a controller!
2

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.

Comments

2

While @aseaSharp answer do (probably) the same, usually you want to disable model validation just on several actions. Here are my few lines:

Attribute class

using Microsoft.AspNetCore.Mvc.ApplicationModels;

namespace D3S.KoFu.WebSite.Helpers;

[AttributeUsage(AttributeTargets.Method)]
public class SuppressModelStateInvalidFilterAttribute : Attribute, IActionModelConvention  
{
    public void Apply(ActionModel action)  
    {  
        for (var i = 0; i < action.Filters.Count; i++)  
        {  
            if (action.Filters[i].GetType().FullName == "Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilterFactory")  
            {  
                action.Filters.RemoveAt(i);  
                break;  
            }  
        }  
    }
}

and standard method decoration like this

[HttpPost]
[SuppressModelStateInvalidFilter]
public IActionResult DoIt([FromBody] MyModel model)
{
   ...
}

Comments

0

Below code worked for me at Single Property level and Entity Level As well -

Example 1 -

public class Personmodel
 {
     [Required]
     public string FirstName { get; set; }

     [ValidateNever]
     public string MiddleName { get; set; }
}

Example 2 -

[ValidateNever]
public class Personmodel
 {

     public string FirstName { get; set; }

     
     public string MiddleName { get; set; }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.