【问题标题】:ASP.NET Core: Prevent Automatic HTTP 400 responses for individual actionASP.NET Core:防止单个操作的自动 HTTP 400 响应
【发布时间】:2019-03-14 03:29:14
【问题描述】:

我喜欢 ASP.NET Core 2.1 中新增的 Automatic HTTP 400 responses 功能,它在大多数情况下运行良好。

但是,在一个操作中,我需要在验证有效负载之前进行一些预处理。我有一个自定义验证器,它需要模型中的两个值来执行验证。其中一个值在路径中,因此我想从路径中在模型上设置该值,然后进行验证。

我不想关闭所有操作的功能:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<ApiBehaviorOptions>(options =>
    {
        options.SuppressModelStateInvalidFilter = true;
    });
}

有什么方法可以让我仅针对个人操作将其关闭吗?

编辑:

我尝试修改 InvalidModelStateResponseFactory 但它没有解决我的问题,因为我仍然需要进入控制器操作:

services.Configure<ApiBehaviorOptions>(options =>
{
    options.InvalidModelStateResponseFactory = actionContext =>
    {
        var ignore = actionContext.ActionDescriptor.FilterDescriptors.Any(fd => fd.Filter is SuppressModelStateInvalidFilterAttribute);
        if (ignore)
        {
            // Can only return IActionResult so doesn't enter the controller action.
        }

        return new BadRequestObjectResult(actionContext.ModelState);
    };
});

[AttributeUsage(AttributeTargets.Method)]
public class SuppressModelStateInvalidFilterAttribute : FormatFilterAttribute
{
}

编辑:

这是我在 asp.net 核心 repo 上提出的问题的链接,以防万一 - https://github.com/aspnet/Mvc/issues/8575

【问题讨论】:

  • 好吧,如果您对添加 3rd 方库感到满意,那么有一个名为 fluent validation 的工具可以帮助验证复杂的模型类型,并且还支持“预验证”逻辑。它可能会有所帮助。这是文档:fluentvalidation.net/start#using-prevalidate

标签: asp.net asp.net-core


【解决方案1】:

这可能通过为您的特定情况实施您自己的验证器来解决。文档中对此进行了很好的介绍。

https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-2.1#custom-validation

使用该模型或自定义模型绑定器来创建模型,并在验证之前完成所有预处理。

【讨论】:

  • 我正在实现一个自定义验证器。我只需要从路径中获取一个值并在验证之前将其设置在模型上。我认为您的自定义活页夹建议可能是要走的路。我会试试的。谢谢。
【解决方案2】:

您可以使用ApiBehaviorOptions.InvalidModelStateResponseFactory 属性来处理基于actionContext 详细信息的特定情况:

services.Configure<ApiBehaviorOptions>(options =>
{
    options.InvalidModelStateResponseFactory = actionContext => 
    {
        // Do what you need here for specific cases with `actionContext` 
        // I believe you can cehck the action attributes 
        // if you'd like to make mark / handle specific cases by action attributes. 

        return new BadRequestObjectResult(context.ModelState);
    }
});

【讨论】:

  • 非常感谢这些建议,我对此寄予厚望,但这并不能解决我的问题。我需要进入控制器操作。只是为了提供一些关于你可以做什么的额外信息,我已经为我的问题添加了一个更新。
【解决方案3】:

我收到了来自 Microsoft 的回复 - https://github.com/aspnet/Mvc/issues/8575

以下内容很有魅力。

[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] is ModelStateInvalidFilter)
            {
                action.Filters.RemoveAt(i);
                break;
            }
        }
    }
}

在我的控制器中,我可以在重新验证之前对模型进行更改(注意 ModelState.Clear(),TryValidateModel 添加到现有模型状态):

if (model == null)
{
    return BadRequest(ModelState);
}

model.Property = valueFromPath;

ModelState.Clear();
if (TryValidateModel(model) == false)
{
    return BadRequest(ModelState);
}

【讨论】:

  • 应该是 action.Filters[i] 是 ModelStateInvalidFilterFactory 但它是内部的 ;/.
【解决方案4】:

更新:您可以在 Startup.cs 的 ConfigureServices 中使用以下代码:

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

根据 Simon Vane 的回答,我不得不修改 ASP.Net Core 2.2 的属性如下:

/// <summary>
/// Suppresses the default ApiController behaviour of automatically creating error 400 responses
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class SuppressModelStateInvalidFilterAttribute : Attribute, IActionModelConvention {
    private static readonly Type ModelStateInvalidFilterFactory = typeof(ModelStateInvalidFilter).Assembly.GetType("Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilterFactory");

    public void Apply(ActionModel action) {
        for (var i = 0; i < action.Filters.Count; i++) {
            if (action.Filters[i] is ModelStateInvalidFilter || action.Filters[i].GetType() == ModelStateInvalidFilterFactory) {
                action.Filters.RemoveAt(i);
                break;
            }
        }
    }
}

【讨论】:

    【解决方案5】:

    我遇到了类似的问题并想出了这个解决方案。

    public class SuppressModelStateInvalidFilterAttribute : ActionFilterAttribute
    {
        public SuppressModelStateInvalidFilterAttribute()
        {
            Order = -2500;
        }
    
        public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            context.ModelState.Clear();
            return next.Invoke();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-08
      • 2019-09-12
      • 2021-01-08
      • 2019-09-11
      • 1970-01-01
      • 1970-01-01
      • 2019-10-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多