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

时间:2018-10-09 11:06:19

标签: asp.net asp.net-core

我喜欢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核心存储库中提出的一个问题的链接,以防万一我遇到问题-https://github.com/aspnet/Mvc/issues/8575

5 个答案:

答案 0 :(得分:2)

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

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

要么验证模型绑定器,要么创建定制模型绑定器,以在验证之前完成所有预处理。

答案 1 :(得分:1)

您可以使用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);
    }
});

答案 2 :(得分:1)

我收到了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);
}

答案 3 :(得分:1)

基于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;
            }
        }
    }
}

答案 4 :(得分:1)

我遇到了类似的问题,并提出了解决方案。

public class SuppressModelStateInvalidFilterAttribute : ActionFilterAttribute
{
    public SuppressModelStateInvalidFilterAttribute()
    {
        Order = -2500;
    }

    public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        context.ModelState.Clear();
        return next.Invoke();
    }
}