ASP.NET Core:防止单个操作的自动 HTTP 400 响应

Sim*_*ane 7 asp.net asp.net-core

我喜欢ASP.NET Core 2.1 新的自动 HTTP 400 响应功能,它在大多数情况下都运行良好。

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

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

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<ApiBehaviorOptions>(options =>
    {
        options.SuppressModelStateInvalidFilter = true;
    });
}
Run Code Online (Sandbox Code Playgroud)

有什么办法可以仅针对个人操作将其关闭?

编辑:

我尝试修改 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
{
}
Run Code Online (Sandbox Code Playgroud)

编辑:

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

Mat*_*Mut 9

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

services.Configure<ApiBehaviorOptions>(apiBehaviorOptions => {
    apiBehaviorOptions.SuppressModelStateInvalidFilter = true;
});
Run Code Online (Sandbox Code Playgroud)

根据 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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Sim*_*ane 5

我收到了 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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

model.Property = valueFromPath;

ModelState.Clear();
if (TryValidateModel(model) == false)
{
    return BadRequest(ModelState);
}
Run Code Online (Sandbox Code Playgroud)

  • 它应该是action.Filters[i]是ModelStateInvalidFilterFactory,但它是内部的;/。 (2认同)

Kar*_*ren 1

这可能可以通过针对您的具体情况实现您自己的验证器来解决。文档中对此进行了很好的介绍。

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

或者是一个自定义模型绑定器,用于创建模型并在验证之前完成所有预处理。