【问题标题】:Correct way to disable model validation in ASP.Net Core 2 MVC在 ASP.Net Core 2 MVC 中禁用模型验证的正确方法
【发布时间】:2018-03-04 15:21:17
【问题描述】:

使用扩展方法设置 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 没有成功,所以想知道是否有更好/正确的方法来关闭验证?

【问题讨论】:

  • 我认为您的解决方案很好。您可以通过以下方式简化依赖项注册:services.AddSingleton<IObjectModelValidator>(new NonValidatingValidator());
  • @thejman 这是正确答案

标签: c# asp.net-mvc validation asp.net-core-2.0


【解决方案1】:
 services.Configure<ApiBehaviorOptions>(options =>
        {
            options.SuppressModelStateInvalidFilter = true;
        });

应该禁用自动模型状态验证。

【讨论】:

  • 这对 asp.net core 3.1 仍然有效吗?还有其他什么我可以禁用来改善我的 api 响应吗?
  • 这个答案是错误的。它只会禁用验证错误的处理程序,但不会禁用验证本身!
  • 它的名字相当难听。我猜过滤器只是在验证失败的情况下处理返回的结果。它不会从一开始就阻止验证的发生。
【解决方案2】:

截至aspnet core 3.1,这是您禁用模型验证的方式,如docs 所示:

首先创建这个 NullValidator 类:

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

    }
}

然后用它代替真实的模型验证器:

services.AddSingleton<IObjectModelValidator, NullObjectModelValidator>();

请注意,这只会禁用模型验证,您仍然会收到模型绑定错误。

【讨论】:

  • 我不认为这真的比@thejman 在问题中的评论增加了很多,但会接受作为结束事情的答案。谢谢!
  • 这个解决方案有一个很大的问题,你应该提防(并且花了我很多时间去发现):当你同时使用这个解决方案 + [ApiController] 属性 [FromHeader]控制器中的参数将始终自动给出 400 错误请求,而无需任何日志记录,因此很难找到问题的根源。
【解决方案3】:

使用此扩展方法:

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

【讨论】:

    【解决方案4】:

    您应该考虑使用ValidateNeverAttribute,它几乎没有被记录在案并且被微软很好地隐藏了。

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

    这使您可以细粒度地控制要验证的实体和不验证的实体。

    【讨论】:

    • 这种方法可能对一些特定的类有用,但是如果你想禁用应用程序范围,我不想装饰我所有的类(并记住将它添加到未来的类中)。在中间件级别做这件事要好得多,并且已经完成了。
    【解决方案5】:

    创建空的模型验证器类。

    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 始终返回 false

    【讨论】:

      【解决方案6】:

      .AddMvc() 扩展方法有一个重载,您可以在其中配置很多东西。其中之一是ModelValidatorProviders 的列表。

      如果您清除此列表,例如:

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

      验证不应再进行。

      【讨论】:

      • 同样不幸的是,这是堆栈的一部分:` Microsoft.AspNetCore.Mvc.Core.dll!Microsoft.AspNetCore.Mvc.Internal.DefaultObjectValidator.Validate(Microsoft.AspNetCore.Mvc.ActionContext actionContext, Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationStateDictionary 验证状态、字符串前缀、对象模型)未知的非用户代码。跳过加载符号。 Microsoft.AspNetCore.Mvc.Core.dll!Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(Microsoft.AspNetCore.Mvc.ActionContext actionContext, Microsoft.AspNetCore.Mvc.ModelBinding.IModelBinder modelBinder`
      • 一样什么?您现在遇到异常了吗?
      • 不,我的意思是它仍在调用 DefaultObjectValidator,我想存在一些代码类似于“我们是否有验证器,如果没有添加 DefaultObjectValidator)
      【解决方案7】:

      关闭所有继承类的验证:

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

      【讨论】:

        猜你喜欢
        • 2011-02-12
        • 1970-01-01
        • 2022-01-21
        • 2011-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多