Skip to main content

Problem details

Overview

RESTful API conventions like NotFoundResultApiConvention, ProblemDetailsResultApiConvention, (see RFC 7807 ). Use this package when implementing RESTful APIs.

Install

  • ASOL.Core.ProblemDetailsConventions - contains RESTful API conventions like NotFoundResultApiConvention, ProblemDetailsResultApiConvention, (see RFC 7807 ). Use this package when implementing RESTful APIs.

Usage third party libraries (NuGets)

Changelog

ASOL.Core.ProblemDetailsConventions

  • 0.0.1.24129-dev
  • 0.0.1.23681-dev
  • 0.0.1.14310-dev

Dependency injection

Mandatory dependency injection for Problem details.

public void ConfigureServices(IServiceCollection services)
{
services.ConfigureOptions<ProblemDetailsOptionsCustomSetup>();
services.AddProblemDetails();
}

public void Configure(IApplicationBuilder app)
{
// Top of pipeline registration
app.UseProblemDetails();
}

Problem details standard base setup

/// <summary>
/// Represents the custom problem details configuration options.
/// </summary>
public class ProblemDetailsOptionsCustomSetup : ProblemDetailsOptionsDefaultSetup
{
public ProblemDetailsOptionsCustomSetup(
IWebHostEnvironment environment,
IHttpContextAccessor httpContextAccessor,
IOptions<ApiBehaviorOptions> apiOptions)
: base(environment, httpContextAccessor, apiOptions)
{
}

/// <inheritdoc/>
public override void Configure(ProblemDetailsOptions options)
{
base.Configure(options);

// This will map KeyNotFoundException to the 404 NotFound code.
options.Map<KeyNotFoundException>(ex =>
new StatusCodeProblemDetails(StatusCodes.Status404NotFound) { Detail = ex.Message });

// This will map InsufficientIdentityException to the 403 Forbidden code.
options.Map<InsufficientIdentityException>(ex =>
new StatusCodeProblemDetails(StatusCodes.Status403Forbidden) { Detail = ex.Message });

// This will map UnauthorizedAccessException to the 403 Forbidden code.
options.Map<UnauthorizedAccessException>(ex =>
new StatusCodeProblemDetails(StatusCodes.Status403Forbidden) { Detail = ex.Message });

// This will map AuthenticationException to the 401 Unauthorized code.
options.Map<AuthenticationException>(ex =>
new StatusCodeProblemDetails(StatusCodes.Status401Unauthorized));

// This will map ArgumentNullException to the 400 BadRequest code.
options.Map<ArgumentNullException>(ex => new ExceptionProblemDetails(ex, StatusCodes.Status400BadRequest));

// This will map processing ValidationException to the 400 BadRequest code.
options.Map<ValidationException>(ex =>
{
var rawStatus = options.MapStatusCode(null, StatusCodes.Status400BadRequest);
var validationErrors = ex.ValidationErrors.ToDictionary();
return new ValidationProblemDetails(validationErrors)
{
Type = rawStatus.Type,
Status = rawStatus.Status,
};
});

options.Map<ProcessingCoreException>(ex =>
{
switch (ex.InnerException)
{
case KeyNotFoundException inner:
{
return new StatusCodeProblemDetails(StatusCodes.Status404NotFound) { Detail = inner.Message };
}
case InsufficientIdentityException inner:
{
return new StatusCodeProblemDetails(StatusCodes.Status403Forbidden) { Detail = inner.Message };
}
case UnauthorizedAccessException inner:
{
return new StatusCodeProblemDetails(StatusCodes.Status403Forbidden) { Detail = inner.Message };
}
case AuthenticationException inner:
{
return new StatusCodeProblemDetails(StatusCodes.Status401Unauthorized);
}
case NotImplementedException inner:
{
return new ExceptionProblemDetails(inner, StatusCodes.Status501NotImplemented);
}
default:
return new ExceptionProblemDetails(ex);
}
});
}
}