diff --git a/README.md b/README.md index 661c61b..bed1b12 100644 --- a/README.md +++ b/README.md @@ -4,61 +4,31 @@ Collection of tools related to problem management (exceptions) that can be gener This library is an ad hoc code customization used in my private/work projects thus avoiding the duplication of repetitive code. -## Configuration in ConfigureServices in Startup.cs - -```csharp - services.AddProblemDetails(); -``` - -## Configuration in Configure in Startup.cs - -```csharp - app.UseProblemDetails(); -``` - -## Example of use - -```csharp - [HttpGet("{id}")] - public async Task GetPerson(Guid id) - { - try - { - var person = await myService.GetItemAsync(id); - - if (person == null) - { - throw new CustomLibrary.ProblemDetails.Exception.NotFoundException($"Person with id {id} not found"); - } - - return Ok(new CustomLibrary.ProblemDetails.Response.Confirm(person)); - } - catch (NotFoundException exc) - { - return CustomLibrary.ProblemDetails.Response.NotFound(HttpContext, exc); - } - } -``` - -# List of Exception Responses - -| Status Codes | Exception | Exception Response | | -| --- | --- | --- | --- | -| 304 | Exception.NotModifiedException | Response.NotModified | available | -| 400 | Exception.BadRequestException | Response.BadRequest | available | -| 401 | Exception.UnauthorizedException | Response.Unauthorized | available | -| 403 | Exception.ForbiddenException | Response.Forbidden | available | -| 404 | Exception.NotFoundException | Response.NotFound | available | -| 405 | Exception.NotAllowedException | Response.MethodNotAllowed | available | -| 406 | Exception.NotAcceptableException | Response.NotAcceptable | available | -| 408 | Exception.RequestTimeoutException | Response.RequestTimeout | available | -| 409 | Exception.ConflictException | Response.Conflict | available | -| 422 | Exception.UnprocessableEntityException | Response.UnprocessableEntity | available | -| 500 | Exception.InternalServerErrorException | Response.InternalServerError | coming soon | -| 501 | Exception.NotImplementedException | Response.NotImplemented | coming soon | -| 502 | Exception.BadGatewayException | Response.BadGateway | coming soon | -| 503 | Exception.ServiceUnavailableException | Response.ServiceUnavailable | coming soon | -| 504 | Exception.GatewayTimeoutException | Response.GatewayTimeout | coming soon | +## How to use ? + +A full example is available in the CustomLibrary.ProblemDetails.Sample folder or click [here](). + +>**Note:** For correct operation it is necessary to add ***services.AddProblemDetails();*** and ***app.UseProblemDetails();*** to the Program class or in the Startup class + +## List of Exception Responses + +| Status Codes | Exception | Status | +| --- | --- | --- | +| 304 | NotModifiedException | available | +| 400 | BadRequestException | available | +| 401 | UnauthorizedException | available | +| 403 | ForbiddenException | available | +| 404 | NotFoundException | available | +| 405 | NotAllowedException | available | +| 406 | NotAcceptableException | available | +| 408 | RequestTimeoutException | available | +| 409 | ConflictException | available | +| 422 | UnprocessableEntityException | available | +| 500 | InternalServerErrorException | available | +| 501 | NotImplementedException | coming soon | +| 502 | BadGatewayException | coming soon | +| 503 | ServiceUnavailableException | coming soon | +| 504 | GatewayTimeoutException | coming soon | ## Contributing diff --git a/src/CustomLibrary.ProblemDetails/Response/Confirm.cs b/src/CustomLibrary.ProblemDetails/Confirm.cs similarity index 93% rename from src/CustomLibrary.ProblemDetails/Response/Confirm.cs rename to src/CustomLibrary.ProblemDetails/Confirm.cs index 86753a7..104dc7b 100644 --- a/src/CustomLibrary.ProblemDetails/Response/Confirm.cs +++ b/src/CustomLibrary.ProblemDetails/Confirm.cs @@ -1,4 +1,4 @@ -namespace CustomLibrary.ProblemDetails.Response; +namespace CustomLibrary.ProblemDetails; public class Confirm { diff --git a/src/CustomLibrary.ProblemDetails/Exception/InternalServerErrorException.cs b/src/CustomLibrary.ProblemDetails/Exception/InternalServerErrorException.cs new file mode 100644 index 0000000..2983040 --- /dev/null +++ b/src/CustomLibrary.ProblemDetails/Exception/InternalServerErrorException.cs @@ -0,0 +1,16 @@ +namespace CustomLibrary.ProblemDetails.Exception; + +public class InternalServerErrorException : System.Exception +{ + public InternalServerErrorException() + { + } + + public InternalServerErrorException(string message) : base(message) + { + } + + public InternalServerErrorException(string message, System.Exception innerException) : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/src/CustomLibrary.ProblemDetails/Response/Response.cs b/src/CustomLibrary.ProblemDetails/ResponseException.cs similarity index 61% rename from src/CustomLibrary.ProblemDetails/Response/Response.cs rename to src/CustomLibrary.ProblemDetails/ResponseException.cs index 3af2ad7..fef63ed 100644 --- a/src/CustomLibrary.ProblemDetails/Response/Response.cs +++ b/src/CustomLibrary.ProblemDetails/ResponseException.cs @@ -1,20 +1,26 @@ -namespace CustomLibrary.ProblemDetails.Response; +namespace CustomLibrary.ProblemDetails; -public static class Response +public static class ResponseException { - public static ObjectResult NotModified(HttpContext httpContext, System.Exception exc) + public static ObjectResult NotModified(HttpContext httpContext, System.Exception exc, List validationError = null) { var statusCode = StatusCodes.Status304NotModified; var problemDetails = new CustomProblemDetails { Status = statusCode, + Detail = exc.Message, Type = $"https://httpstatuses.com/{statusCode}", Instance = httpContext.Request.Path, Title = "NotModified" }; problemDetails.Extensions.Add("traceId", Activity.Current?.Id ?? httpContext.TraceIdentifier); - problemDetails.Extensions.Add("errors", exc.Message); + //problemDetails.Extensions.Add("errors", exc.Message); + + if (validationError?.Any() ?? false) + { + problemDetails.Extensions.Add("errors", validationError); + } var result = new ObjectResult(problemDetails) { @@ -24,19 +30,25 @@ public static ObjectResult NotModified(HttpContext httpContext, System.Exception return result; } - public static ObjectResult BadRequest(HttpContext httpContext, System.Exception exc) + public static ObjectResult BadRequest(HttpContext httpContext, System.Exception exc, List validationError = null) { var statusCode = StatusCodes.Status400BadRequest; var problemDetails = new CustomProblemDetails { Status = statusCode, + Detail = exc.Message, Type = $"https://httpstatuses.com/{statusCode}", Instance = httpContext.Request.Path, Title = "BadRequest" }; problemDetails.Extensions.Add("traceId", Activity.Current?.Id ?? httpContext.TraceIdentifier); - problemDetails.Extensions.Add("errors", exc.Message); + //problemDetails.Extensions.Add("errors", exc.Message); + + if (validationError?.Any() ?? false) + { + problemDetails.Extensions.Add("errors", validationError); + } var result = new ObjectResult(problemDetails) { @@ -46,19 +58,25 @@ public static ObjectResult BadRequest(HttpContext httpContext, System.Exception return result; } - public static ObjectResult Unauthorized(HttpContext httpContext, System.Exception exc) + public static ObjectResult Unauthorized(HttpContext httpContext, System.Exception exc, List validationError = null) { var statusCode = StatusCodes.Status401Unauthorized; var problemDetails = new CustomProblemDetails { Status = statusCode, + Detail = exc.Message, Type = $"https://httpstatuses.com/{statusCode}", Instance = httpContext.Request.Path, Title = "Unauthorized" }; problemDetails.Extensions.Add("traceId", Activity.Current?.Id ?? httpContext.TraceIdentifier); - problemDetails.Extensions.Add("errors", exc.Message); + //problemDetails.Extensions.Add("errors", exc.Message); + + if (validationError?.Any() ?? false) + { + problemDetails.Extensions.Add("errors", validationError); + } var result = new ObjectResult(problemDetails) { @@ -68,19 +86,25 @@ public static ObjectResult Unauthorized(HttpContext httpContext, System.Exceptio return result; } - public static ObjectResult Forbidden(HttpContext httpContext, System.Exception exc) + public static ObjectResult Forbidden(HttpContext httpContext, System.Exception exc, List validationError = null) { var statusCode = StatusCodes.Status403Forbidden; var problemDetails = new CustomProblemDetails { Status = statusCode, + Detail = exc.Message, Type = $"https://httpstatuses.com/{statusCode}", Instance = httpContext.Request.Path, Title = "Forbidden" }; problemDetails.Extensions.Add("traceId", Activity.Current?.Id ?? httpContext.TraceIdentifier); - problemDetails.Extensions.Add("errors", exc.Message); + //problemDetails.Extensions.Add("errors", exc.Message); + + if (validationError?.Any() ?? false) + { + problemDetails.Extensions.Add("errors", validationError); + } var result = new ObjectResult(problemDetails) { @@ -90,19 +114,25 @@ public static ObjectResult Forbidden(HttpContext httpContext, System.Exception e return result; } - public static ObjectResult NotFound(HttpContext httpContext, System.Exception exc) + public static ObjectResult NotFound(HttpContext httpContext, System.Exception exc, List validationError = null) { var statusCode = StatusCodes.Status404NotFound; var problemDetails = new CustomProblemDetails { Status = statusCode, + Detail = exc.Message, Type = $"https://httpstatuses.com/{statusCode}", Instance = httpContext.Request.Path, Title = "NotFound" }; problemDetails.Extensions.Add("traceId", Activity.Current?.Id ?? httpContext.TraceIdentifier); - problemDetails.Extensions.Add("errors", exc.Message); + //problemDetails.Extensions.Add("errors", exc.Message); + + if (validationError?.Any() ?? false) + { + problemDetails.Extensions.Add("errors", validationError); + } var result = new ObjectResult(problemDetails) { @@ -112,19 +142,25 @@ public static ObjectResult NotFound(HttpContext httpContext, System.Exception ex return result; } - public static ObjectResult MethodNotAllowed(HttpContext httpContext, System.Exception exc) + public static ObjectResult MethodNotAllowed(HttpContext httpContext, System.Exception exc, List validationError = null) { var statusCode = StatusCodes.Status405MethodNotAllowed; var problemDetails = new CustomProblemDetails { Status = statusCode, + Detail = exc.Message, Type = $"https://httpstatuses.com/{statusCode}", Instance = httpContext.Request.Path, Title = "MethodNotAllowed" }; problemDetails.Extensions.Add("traceId", Activity.Current?.Id ?? httpContext.TraceIdentifier); - problemDetails.Extensions.Add("errors", exc.Message); + //problemDetails.Extensions.Add("errors", exc.Message); + + if (validationError?.Any() ?? false) + { + problemDetails.Extensions.Add("errors", validationError); + } var result = new ObjectResult(problemDetails) { @@ -134,19 +170,25 @@ public static ObjectResult MethodNotAllowed(HttpContext httpContext, System.Exce return result; } - public static ObjectResult NotAcceptable(HttpContext httpContext, System.Exception exc) + public static ObjectResult NotAcceptable(HttpContext httpContext, System.Exception exc, List validationError = null) { var statusCode = StatusCodes.Status406NotAcceptable; var problemDetails = new CustomProblemDetails { Status = statusCode, + Detail = exc.Message, Type = $"https://httpstatuses.com/{statusCode}", Instance = httpContext.Request.Path, Title = "NotAcceptable" }; problemDetails.Extensions.Add("traceId", Activity.Current?.Id ?? httpContext.TraceIdentifier); - problemDetails.Extensions.Add("errors", exc.Message); + //problemDetails.Extensions.Add("errors", exc.Message); + + if (validationError?.Any() ?? false) + { + problemDetails.Extensions.Add("errors", validationError); + } var result = new ObjectResult(problemDetails) { @@ -156,19 +198,25 @@ public static ObjectResult NotAcceptable(HttpContext httpContext, System.Excepti return result; } - public static ObjectResult RequestTimeout(HttpContext httpContext, System.Exception exc) + public static ObjectResult RequestTimeout(HttpContext httpContext, System.Exception exc, List validationError = null) { var statusCode = StatusCodes.Status408RequestTimeout; var problemDetails = new CustomProblemDetails { Status = statusCode, + Detail = exc.Message, Type = $"https://httpstatuses.com/{statusCode}", Instance = httpContext.Request.Path, Title = "RequestTimeout" }; problemDetails.Extensions.Add("traceId", Activity.Current?.Id ?? httpContext.TraceIdentifier); - problemDetails.Extensions.Add("errors", exc.Message); + //problemDetails.Extensions.Add("errors", exc.Message); + + if (validationError?.Any() ?? false) + { + problemDetails.Extensions.Add("errors", validationError); + } var result = new ObjectResult(problemDetails) { @@ -178,19 +226,25 @@ public static ObjectResult RequestTimeout(HttpContext httpContext, System.Except return result; } - public static ObjectResult Conflict(HttpContext httpContext, System.Exception exc) + public static ObjectResult Conflict(HttpContext httpContext, System.Exception exc, List validationError = null) { var statusCode = StatusCodes.Status409Conflict; var problemDetails = new CustomProblemDetails { Status = statusCode, + Detail = exc.Message, Type = $"https://httpstatuses.com/{statusCode}", Instance = httpContext.Request.Path, Title = "Conflict" }; problemDetails.Extensions.Add("traceId", Activity.Current?.Id ?? httpContext.TraceIdentifier); - problemDetails.Extensions.Add("errors", exc.Message); + //problemDetails.Extensions.Add("errors", exc.Message); + + if (validationError?.Any() ?? false) + { + problemDetails.Extensions.Add("errors", validationError); + } var result = new ObjectResult(problemDetails) { @@ -200,19 +254,53 @@ public static ObjectResult Conflict(HttpContext httpContext, System.Exception ex return result; } - public static ObjectResult UnprocessableEntity(HttpContext httpContext, System.Exception exc) + public static ObjectResult UnprocessableEntity(HttpContext httpContext, System.Exception exc, List validationError = null) { var statusCode = StatusCodes.Status422UnprocessableEntity; var problemDetails = new CustomProblemDetails { Status = statusCode, + Detail = exc.Message, Type = $"https://httpstatuses.com/{statusCode}", Instance = httpContext.Request.Path, Title = "UnprocessableEntity" }; problemDetails.Extensions.Add("traceId", Activity.Current?.Id ?? httpContext.TraceIdentifier); - problemDetails.Extensions.Add("errors", exc.Message); + //problemDetails.Extensions.Add("errors", exc.Message); + + if (validationError?.Any() ?? false) + { + problemDetails.Extensions.Add("errors", validationError); + } + + var result = new ObjectResult(problemDetails) + { + StatusCode = statusCode + }; + + return result; + } + + public static ObjectResult InternalServerError(HttpContext httpContext, System.Exception exc, List validationError = null) + { + var statusCode = StatusCodes.Status500InternalServerError; + var problemDetails = new CustomProblemDetails + { + Status = statusCode, + Detail = exc.Message, + Type = $"https://httpstatuses.com/{statusCode}", + Instance = httpContext.Request.Path, + Title = "InternalServerError" + }; + + problemDetails.Extensions.Add("traceId", Activity.Current?.Id ?? httpContext.TraceIdentifier); + //problemDetails.Extensions.Add("errors", exc.Message); + + if (validationError?.Any() ?? false) + { + problemDetails.Extensions.Add("errors", validationError); + } var result = new ObjectResult(problemDetails) {