ASP.NET Core 2.2-问题详细信息

时间:2019-02-24 11:05:31

标签: 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": {}
}

根据Microsoft,这是预期的-我对此感到满意。

但是,由于某些原因,我的项目不会针对某些默认返回码(例如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结尾,但没有附加任何问题详细信息。我不知道应该发生什么,而且我无法弄清楚要实现它需要按下哪个开关。

1 个答案:

答案 0 :(得分:1)

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

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

public class ExceptionMiddleware
{
    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();
            return;
        }
    }

    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中的所有异常都作为“问题详细信息”返回,所以我创建了一个名为HttpExceptions的NuGet包,可以为您做到这一点:)看看,也许是也是您的理想解决方案。