简体   繁体   中英

ASP.NET Core 2.2 - ProblemDetails

I've upgraded my ASP.NET Core project with Swagger support to 2.2 recently. I noticed that all my error responses now show with a ProblemDetails response body.

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

According to Microsoft this is expected - and I'm happy with it.

However, for some reason my project does not return these for some default return codes such as 401. This is (what I believe is) the relevant part of my startup config.

    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(...});

With this setup any unauthorized request ends up in a 401, but without any problem details attached. That's not what I understood should happen, and I cannot figure out which switch I need to press to make it happen.

By default only for 400 BadRequests when model validation failed Problem Details are returned. This is done by a filter that is automatically inserted when you add the ApiController attribute to your controller. This behavior can be influenced from the ApiBehaviorOptions in the case of the filter specifically the InvalidModelStateResponseFactory .

Other exceptions that occur are also not mapped to problem details, for that you have to write your own middleware. Something like the following:

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));
    }
}

But this will still not return 401 Unauthorized as Problem Details for that you should capture the HttpResponse in your middleware and transform that to Problem Details as well.

But because I had the same issues and wanted all the exceptions from my APIs to be returned as Problem Details, I've created a NuGet package, called HttpExceptions, that does that for you :) Have a look and maybe it is also a good solution for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM