首页 > 解决方案 > ASP.NET Core 2.2 - 问题详情

问题描述

我最近将支持 Swagger 的 ASP.NET Core 项目升级到了 2.2。我注意到我所有的错误响应现在都显示有一个 ProblemDetails 响应正文。

{
  "type": "string",
  "title": "string",
  "status": 0,
  "detail": "string",
  "instance": "string",
  "additionalProp1": {},
  "additionalProp2": {},
  "additionalProp3": {}
}

根据微软的说法,这是意料之中的——我对此很满意。

但是,由于某种原因,我的项目不会为某些默认返回代码(例如 401)返回这些。这是(我相信是)我的启动配置的相关部分。

    services
        .AddAuthentication(options => {
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(jwtOptions => {
            jwtOptions.Authority = jwtConfiguration.Authority;
            jwtOptions.TokenValidationParameters.ValidAudiences = jwtConfiguration.Audiences;
        });

    // Add framework services.
    services
        .AddMvcCore(options => {
            options.Filters.Add<OperationCancelledExceptionFilterAttribute>();
        })
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
        .AddAuthorization()
        .AddApiExplorer()
        .AddJsonFormatters()
        .AddCors()
        .AddJsonOptions(options => options.SerializerSettings.Converters.Add(new StringEnumConverter()));

    services.AddVersionedApiExplorer(
        options => {
            //The format of the version added to the route URL  
            options.GroupNameFormat = "'v'VVV";
            //Tells swagger to replace the version in the controller route  
            options.SubstituteApiVersionInUrl = true;
        });

    services.AddApiVersioning(option => {
        option.ReportApiVersions = true;
    });

    // Add data protection
    services.AddDataProtection();

    //Add swagger
    services.AddSwaggerGen(c => {
        c.SwaggerDoc("v1", new Info { Version = "1.0", ...});
        c.SwaggerDoc("v2", new Info { Version = "2.0", ...});
        c.AddSecurityDefinition("Bearer", ...});
        c.AddSecurityRequirement(...);
        c.DescribeAllEnumsAsStrings();
        c.EnableAnnotations();
    });

    //Add documentation for end point
    services.AddSwaggerGen(...});

使用此设置,任何未经授权的请求都会以 401 告终,但不会附加任何问题详细信息。这不是我所理解的应该发生的事情,我无法弄清楚我需要按下哪个开关来实现它。

标签: c#asp.net-core-2.2

解决方案


默认情况下,仅当模型验证失败时返回 400 BadRequests 问题详细信息。这是通过将 ApiController 属性添加到控制器时自动插入的过滤器来完成的。ApiBehaviorOptions在过滤器的情况下,这种行为可能会受到影响,特别是InvalidModelStateResponseFactory.

发生的其他异常也不会映射到问题详细信息,因为您必须编写自己的中间件。类似于以下内容:

public class ExceptionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IActionResultExecutor<ObjectResult> _executor;

    public ExceptionMiddleware(RequestDelegate next, IActionResultExecutor<ObjectResult> executor)
    {
        _next = next;
        _executor = executor;
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await _next(context);
        } 
        catch(Exception ex) 
        {
            await ExecuteProblemDetailsResultAsync(context, ex);
        }
    }

    private Task ExecuteProblemDetailsResultAsync(HttpContext context, Exception ex)
    {
        var routeData = context.GetRouteData();
        var actionContext = new ActionContext(context, routeData, new ActionDescriptor());

        var problemDetails = ex.ToProblemDetails();
        return _executor.ExecuteAsync(actionContext, new ObjectResult(problemDetails));
    }
}

但这仍然不会返回 401 Unauthorized 作为问题详细信息,因为您应该在中间件中捕获 HttpResponse 并将其转换为问题详细信息。

但是因为我遇到了同样的问题,并且希望我的 API 中的所有异常都作为问题详细信息返回,所以我创建了一个 NuGet 包,称为 HttpExceptions,它可以为您做到这一点:) 看看,也许它也是一个不错的选择为您解决。


推荐阅读