ASP.NET 核心 2.2 - 问题详情

ASP.NET Core 2.2 - ProblemDetails

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

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

根据 Microsoft 的说法,这是预期的 - 我对此很满意。

但是,由于某些原因,我的项目没有 return 这些默认 return 代码,例如 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 结束,但不会附加任何问题详细信息。这不是我所理解的应该发生的事情,而且我无法弄清楚我需要按下哪个开关才能实现它。

默认情况下,模型验证失败时仅针对 400 个 BadRequests 问题详细信息 returned。这是通过将 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));
    }
}

但这仍然不会 return 401 Unauthorized as Problem Details 为此,您应该在中间件中捕获 HttpResponse 并将其转换为问题详细信息。

但是因为我遇到了同样的问题并且希望我的 API 中的所有异常都被 return 编辑为问题详细信息,所以我创建了一个名为 HttpExceptions 的 NuGet 包,它可以为您做到这一点:)看看吧,也许对你来说也是一个不错的解决方案。