在 ASP.Net Core 2 MVC 中禁用模型验证的正确方法
Correct way to disable model validation in ASP.Net Core 2 MVC
使用扩展方法设置 MVC
services.AddMvc()
然后在控制器中,这也可能适用于 GET,为 POST 操作创建一个方法,并在正文中提供一个参数,例如
[HttpPost("save")]
public Entity Save([FromBody]Entity someEntity)
当调用动作时,MVC 管道将调用 ParameterBinder,后者又调用 DefaultObjectValidator
。我不想要验证(一方面它很慢,但更重要的是在复杂的循环图上循环),但似乎关闭管道中验证的唯一方法是这样的:
public class NonValidatingValidator : IObjectModelValidator
{
public void Validate(ActionContext actionContext, ValidationStateDictionary validationState, string prefix, object model)
{
}
}
并在 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));
}
这看起来像一把大锤。我环顾四周,找不到替代方案,也尝试删除 DataAnnotationModelValidator
但没有成功,所以想知道是否有 better/correct 关闭验证的方法?
.AddMvc()
扩展方法有一个重载,您可以在其中配置很多东西。其中之一就是 ModelValidatorProviders
的列表。
如果您清除此列表,例如:
services.AddMvc(options => options.ModelValidatorProviders.Clear());
不应再进行验证。
使用此扩展方法:
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)
{
}
}
用法:
public void ConfigureServices(IServiceCollection services)
{
services.DisableDefaultModelValidation();
}
创建空模型验证器class。
public class EmptyModelValidator : IObjectModelValidator {
public void Validate(
ActionContext actionContext,
ValidationStateDictionary validationState,
string prefix,
object model) {
}
}
在配置服务方法中将 DefaultModelValidator 替换为 EmptyModelValidator。
services.Replace(
new ServiceDescriptor(typeof(IObjectModelValidator),
typeof(EmptyModelValidator),
ServiceLifetime.Singleton)
);
EmptyModelValidator 不验证模型,因此 ModelState.IsValid 总是 return false
.
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
应该禁用自动模型状态验证。
从 aspnet core 3.1
开始,这是您禁用模型验证的方式,如 docs 中所示:
首先创建这个 NullValidator class:
public class NullObjectModelValidator : IObjectModelValidator
{
public void Validate(ActionContext actionContext,
ValidationStateDictionary validationState, string prefix, object model)
{
}
}
然后用它代替真正的模型验证器:
services.AddSingleton<IObjectModelValidator, NullObjectModelValidator>();
请注意,这只会禁用模型验证,您仍然会遇到模型绑定错误。
您应该考虑使用 ValidateNeverAttribute,它几乎没有记录并且被 Microsoft 隐藏得很好。
[ValidateNever]
public class Entity
{
....
}
这使您可以精细控制要验证哪些实体,哪些不验证。
关闭所有继承 class 的验证:
var mvc = services.AddMvc(options =>
{
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(VMClass)));
}); // to avoid validation of the complete world by following VMClass refs
使用扩展方法设置 MVC
services.AddMvc()
然后在控制器中,这也可能适用于 GET,为 POST 操作创建一个方法,并在正文中提供一个参数,例如
[HttpPost("save")]
public Entity Save([FromBody]Entity someEntity)
当调用动作时,MVC 管道将调用 ParameterBinder,后者又调用 DefaultObjectValidator
。我不想要验证(一方面它很慢,但更重要的是在复杂的循环图上循环),但似乎关闭管道中验证的唯一方法是这样的:
public class NonValidatingValidator : IObjectModelValidator
{
public void Validate(ActionContext actionContext, ValidationStateDictionary validationState, string prefix, object model)
{
}
}
并在 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));
}
这看起来像一把大锤。我环顾四周,找不到替代方案,也尝试删除 DataAnnotationModelValidator
但没有成功,所以想知道是否有 better/correct 关闭验证的方法?
.AddMvc()
扩展方法有一个重载,您可以在其中配置很多东西。其中之一就是 ModelValidatorProviders
的列表。
如果您清除此列表,例如:
services.AddMvc(options => options.ModelValidatorProviders.Clear());
不应再进行验证。
使用此扩展方法:
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)
{
}
}
用法:
public void ConfigureServices(IServiceCollection services)
{
services.DisableDefaultModelValidation();
}
创建空模型验证器class。
public class EmptyModelValidator : IObjectModelValidator {
public void Validate(
ActionContext actionContext,
ValidationStateDictionary validationState,
string prefix,
object model) {
}
}
在配置服务方法中将 DefaultModelValidator 替换为 EmptyModelValidator。
services.Replace(
new ServiceDescriptor(typeof(IObjectModelValidator),
typeof(EmptyModelValidator),
ServiceLifetime.Singleton)
);
EmptyModelValidator 不验证模型,因此 ModelState.IsValid 总是 return false
.
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
应该禁用自动模型状态验证。
从 aspnet core 3.1
开始,这是您禁用模型验证的方式,如 docs 中所示:
首先创建这个 NullValidator class:
public class NullObjectModelValidator : IObjectModelValidator
{
public void Validate(ActionContext actionContext,
ValidationStateDictionary validationState, string prefix, object model)
{
}
}
然后用它代替真正的模型验证器:
services.AddSingleton<IObjectModelValidator, NullObjectModelValidator>();
请注意,这只会禁用模型验证,您仍然会遇到模型绑定错误。
您应该考虑使用 ValidateNeverAttribute,它几乎没有记录并且被 Microsoft 隐藏得很好。
[ValidateNever]
public class Entity
{
....
}
这使您可以精细控制要验证哪些实体,哪些不验证。
关闭所有继承 class 的验证:
var mvc = services.AddMvc(options =>
{
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(VMClass)));
}); // to avoid validation of the complete world by following VMClass refs