首页 > 解决方案 > .net Core - 添加过滤器时忽略响应类型

问题描述

startup.cs我为所有错误响应添加过滤器时,我通过抛出异常返回自己的错误对象(ErrorResponse),在中间件中我返回此代码作为响应。但是这些错误不是控制器方法中的返回类型,所以我必须为所有响应添加过滤器。它有效,在 swagger.json 中有这些响应,但没有响应类型(200),只有错误响应。

services.AddMvc(options =>
{
 options.EnableEndpointRouting = false;
 options.Filters.Add(new Microsoft.AspNetCore.Mvc.ProducesResponseTypeAttribute(typeof(ErrorResponse), (int)HttpStatusCode.BadRequest));
 options.Filters.Add(new Microsoft.AspNetCore.Mvc.ProducesResponseTypeAttribute(typeof(ErrorResponse), (int)HttpStatusCode.Unauthorized));
 options.Filters.Add(new Microsoft.AspNetCore.Mvc.ProducesResponseTypeAttribute(typeof(ErrorResponse), (int)HttpStatusCode.NotFound));
 options.Filters.Add(new Microsoft.AspNetCore.Mvc.ProducesResponseTypeAttribute(typeof(ErrorResponse), (int)HttpStatusCode.InternalServerError));
})

示例图像

有人知道如何从控制器方法中保留默认返回类型吗?

谢谢你。:-)

标签: c#asp.net-coreswagger

解决方案


虽然我不完全确定为什么过滤器最终会删除由 给出的默认 200 响应类型ActionResult<T>,但这是另一种可以完成的方法,尽管需要更多代码。此代码基于此答案

public class ProduceResponseTypeModelProvider : IApplicationModelProvider
{
    public int Order => 3;

    public void OnProvidersExecuted(ApplicationModelProviderContext context)
    {
    }

    public void OnProvidersExecuting(ApplicationModelProviderContext context)
    {
        var actions = context.Result.Controllers
            .SelectMany(x => x.Actions);

        foreach (var action in actions)
        {
            var returnType = action.ActionMethod.ReturnType;

            // if the action returns Task<T>, use that T as the return type
            if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
            {
                returnType = returnType.GenericTypeArguments[0];
            }

            // if returnType is an ActionResult<T>, use that T for a 200 OK response
            if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(ActionResult<>))
            {
                var innerReturnType = returnType.GetGenericArguments()[0];

                action.Filters.Add(new ProducesResponseTypeAttribute(innerReturnType, StatusCodes.Status200OK));
            }
            // otherwise, if the type is only IActionResult, return 204 No Content
            else if (returnType == typeof(IActionResult))
            {
                action.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status204NoContent));
            }

            // if there are input parameters, add 400 Bad Request as a possible result
            if (action.Parameters.Count > 0)
            {
                action.Filters.Add(new ProducesResponseTypeAttribute(typeof(ProblemDetails), StatusCodes.Status400BadRequest));
            }

            // add common response types
            action.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status401Unauthorized));
            action.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status403Forbidden));
            action.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status404NotFound));
            action.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status500InternalServerError));
        }
    }
}

了解如何调整上述内容以返回ErrorResponse特定响应应该相当简单。

上面可以注入:

services.TryAddEnumerable(ServiceDescriptor.Transient<IApplicationModelProvider, ProduceResponseTypeModelProvider>());

推荐阅读