Merge pull request #246 from meysamhadeli/chore/update_problem_details_extensions

chore: Update problem details extensions for more additional info
This commit is contained in:
Meysam Hadeli 2023-04-07 17:19:01 +03:30 committed by GitHub
commit 5954846d69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 144 additions and 48 deletions

View File

@ -4,14 +4,39 @@ using BuildingBlocks.Exception;
using Grpc.Core; using Grpc.Core;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
public static class ProblemDetailsExtensions public static class ProblemDetailsExtensions
{ {
public static WebApplication UseCustomProblemDetails(this WebApplication app) public static WebApplication UseCustomProblemDetails(this WebApplication app)
{ {
app.UseStatusCodePages(statusCodeHandlerApp =>
{
statusCodeHandlerApp.Run(async context =>
{
context.Response.ContentType = "application/problem+json";
if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)
{
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Detail = ReasonPhrases.GetReasonPhrase(context.Response.StatusCode),
Status = context.Response.StatusCode
}
});
}
});
});
app.UseExceptionHandler(exceptionHandlerApp => app.UseExceptionHandler(exceptionHandlerApp =>
{ {
exceptionHandlerApp.Run(async context => exceptionHandlerApp.Run(async context =>
@ -20,82 +45,81 @@ public static class ProblemDetailsExtensions
if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService) if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)
{ {
var env = context.RequestServices.GetRequiredService<IWebHostEnvironment>();
var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>(); var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error; var exceptionType = exceptionHandlerFeature?.Error;
if (exceptionType is not null) if (exceptionType is not null)
{ {
(string Detail, string Type, string Title, int StatusCode) details = exceptionType switch (string Detail, string Title, int StatusCode) details = exceptionType switch
{ {
ConflictException => ConflictException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.8",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict context.Response.StatusCode = StatusCodes.Status409Conflict
), ),
ValidationException validationException => ValidationException validationException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = (int)validationException.StatusCode context.Response.StatusCode = (int)validationException.StatusCode
), ),
BadRequestException => BadRequestException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest context.Response.StatusCode = StatusCodes.Status400BadRequest
), ),
NotFoundException => NotFoundException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.4",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status404NotFound context.Response.StatusCode = StatusCodes.Status404NotFound
), ),
AppException => AppException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest context.Response.StatusCode = StatusCodes.Status400BadRequest
), ),
DbUpdateConcurrencyException => DbUpdateConcurrencyException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.8",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict context.Response.StatusCode = StatusCodes.Status409Conflict
), ),
RpcException => RpcException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest context.Response.StatusCode = StatusCodes.Status400BadRequest
), ),
_ => _ =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.6.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status500InternalServerError context.Response.StatusCode = StatusCodes.Status500InternalServerError
) )
}; };
await problemDetailsService.WriteAsync(new ProblemDetailsContext var problem = new ProblemDetailsContext
{ {
HttpContext = context, HttpContext = context,
ProblemDetails = ProblemDetails =
{ {
Title = details.Title, Title = details.Title,
Detail = details.Detail, Detail = details.Detail,
Type = details.Type,
Status = details.StatusCode Status = details.StatusCode
} }
}); };
if (env.IsDevelopment())
{
problem.ProblemDetails.Extensions.Add("exception", exceptionHandlerFeature?.Error.ToString());
}
await problemDetailsService.WriteAsync(problem);
} }
} }
}); });

View File

@ -7,12 +7,37 @@ namespace Flight.Extensions.Infrastructure;
using Grpc.Core; using Grpc.Core;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
public static class ProblemDetailsExtensions public static class ProblemDetailsExtensions
{ {
public static WebApplication UseCustomProblemDetails(this WebApplication app) public static WebApplication UseCustomProblemDetails(this WebApplication app)
{ {
app.UseStatusCodePages(statusCodeHandlerApp =>
{
statusCodeHandlerApp.Run(async context =>
{
context.Response.ContentType = "application/problem+json";
if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)
{
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Detail = ReasonPhrases.GetReasonPhrase(context.Response.StatusCode),
Status = context.Response.StatusCode
}
});
}
});
});
app.UseExceptionHandler(exceptionHandlerApp => app.UseExceptionHandler(exceptionHandlerApp =>
{ {
exceptionHandlerApp.Run(async context => exceptionHandlerApp.Run(async context =>
@ -21,82 +46,81 @@ public static class ProblemDetailsExtensions
if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService) if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)
{ {
var env = context.RequestServices.GetRequiredService<IWebHostEnvironment>();
var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>(); var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error; var exceptionType = exceptionHandlerFeature?.Error;
if (exceptionType is not null) if (exceptionType is not null)
{ {
(string Detail, string Type, string Title, int StatusCode) details = exceptionType switch (string Detail, string Title, int StatusCode) details = exceptionType switch
{ {
ConflictException => ConflictException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.8",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict context.Response.StatusCode = StatusCodes.Status409Conflict
), ),
ValidationException validationException => ValidationException validationException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = (int)validationException.StatusCode context.Response.StatusCode = (int)validationException.StatusCode
), ),
BadRequestException => BadRequestException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest context.Response.StatusCode = StatusCodes.Status400BadRequest
), ),
NotFoundException => NotFoundException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.4",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status404NotFound context.Response.StatusCode = StatusCodes.Status404NotFound
), ),
AppException => AppException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest context.Response.StatusCode = StatusCodes.Status400BadRequest
), ),
DbUpdateConcurrencyException => DbUpdateConcurrencyException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.8",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict context.Response.StatusCode = StatusCodes.Status409Conflict
), ),
RpcException => RpcException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest context.Response.StatusCode = StatusCodes.Status400BadRequest
), ),
_ => _ =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.6.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status500InternalServerError context.Response.StatusCode = StatusCodes.Status500InternalServerError
) )
}; };
await problemDetailsService.WriteAsync(new ProblemDetailsContext var problem = new ProblemDetailsContext
{ {
HttpContext = context, HttpContext = context,
ProblemDetails = ProblemDetails =
{ {
Title = details.Title, Title = details.Title,
Detail = details.Detail, Detail = details.Detail,
Type = details.Type,
Status = details.StatusCode Status = details.StatusCode
} }
}); };
if (env.IsDevelopment())
{
problem.ProblemDetails.Extensions.Add("exception", exceptionHandlerFeature?.Error.ToString());
}
await problemDetailsService.WriteAsync(problem);
} }
} }
}); });

View File

@ -4,14 +4,39 @@ using BuildingBlocks.Exception;
using Grpc.Core; using Grpc.Core;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
public static class ProblemDetailsExtensions public static class ProblemDetailsExtensions
{ {
public static WebApplication UseCustomProblemDetails(this WebApplication app) public static WebApplication UseCustomProblemDetails(this WebApplication app)
{ {
app.UseStatusCodePages(statusCodeHandlerApp =>
{
statusCodeHandlerApp.Run(async context =>
{
context.Response.ContentType = "application/problem+json";
if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)
{
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Detail = ReasonPhrases.GetReasonPhrase(context.Response.StatusCode),
Status = context.Response.StatusCode
}
});
}
});
});
app.UseExceptionHandler(exceptionHandlerApp => app.UseExceptionHandler(exceptionHandlerApp =>
{ {
exceptionHandlerApp.Run(async context => exceptionHandlerApp.Run(async context =>
@ -20,82 +45,81 @@ public static class ProblemDetailsExtensions
if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService) if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)
{ {
var env = context.RequestServices.GetRequiredService<IWebHostEnvironment>();
var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>(); var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error; var exceptionType = exceptionHandlerFeature?.Error;
if (exceptionType is not null) if (exceptionType is not null)
{ {
(string Detail, string Type, string Title, int StatusCode) details = exceptionType switch (string Detail, string Title, int StatusCode) details = exceptionType switch
{ {
ConflictException => ConflictException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.8",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict context.Response.StatusCode = StatusCodes.Status409Conflict
), ),
ValidationException validationException => ValidationException validationException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = (int)validationException.StatusCode context.Response.StatusCode = (int)validationException.StatusCode
), ),
BadRequestException => BadRequestException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest context.Response.StatusCode = StatusCodes.Status400BadRequest
), ),
NotFoundException => NotFoundException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.4",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status404NotFound context.Response.StatusCode = StatusCodes.Status404NotFound
), ),
AppException => AppException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest context.Response.StatusCode = StatusCodes.Status400BadRequest
), ),
DbUpdateConcurrencyException => DbUpdateConcurrencyException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.8",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict context.Response.StatusCode = StatusCodes.Status409Conflict
), ),
RpcException => RpcException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest context.Response.StatusCode = StatusCodes.Status400BadRequest
), ),
_ => _ =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.6.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status500InternalServerError context.Response.StatusCode = StatusCodes.Status500InternalServerError
) )
}; };
await problemDetailsService.WriteAsync(new ProblemDetailsContext var problem = new ProblemDetailsContext
{ {
HttpContext = context, HttpContext = context,
ProblemDetails = ProblemDetails =
{ {
Title = details.Title, Title = details.Title,
Detail = details.Detail, Detail = details.Detail,
Type = details.Type,
Status = details.StatusCode Status = details.StatusCode
} }
}); };
if (env.IsDevelopment())
{
problem.ProblemDetails.Extensions.Add("exception", exceptionHandlerFeature?.Error.ToString());
}
await problemDetailsService.WriteAsync(problem);
} }
} }
}); });

View File

@ -4,14 +4,39 @@ using BuildingBlocks.Exception;
using Grpc.Core; using Grpc.Core;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
public static class ProblemDetailsExtensions public static class ProblemDetailsExtensions
{ {
public static WebApplication UseCustomProblemDetails(this WebApplication app) public static WebApplication UseCustomProblemDetails(this WebApplication app)
{ {
app.UseStatusCodePages(statusCodeHandlerApp =>
{
statusCodeHandlerApp.Run(async context =>
{
context.Response.ContentType = "application/problem+json";
if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)
{
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Detail = ReasonPhrases.GetReasonPhrase(context.Response.StatusCode),
Status = context.Response.StatusCode
}
});
}
});
});
app.UseExceptionHandler(exceptionHandlerApp => app.UseExceptionHandler(exceptionHandlerApp =>
{ {
exceptionHandlerApp.Run(async context => exceptionHandlerApp.Run(async context =>
@ -20,82 +45,81 @@ public static class ProblemDetailsExtensions
if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService) if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)
{ {
var env = context.RequestServices.GetRequiredService<IWebHostEnvironment>();
var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>(); var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error; var exceptionType = exceptionHandlerFeature?.Error;
if (exceptionType is not null) if (exceptionType is not null)
{ {
(string Detail, string Type, string Title, int StatusCode) details = exceptionType switch (string Detail, string Title, int StatusCode) details = exceptionType switch
{ {
ConflictException => ConflictException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.8",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict context.Response.StatusCode = StatusCodes.Status409Conflict
), ),
ValidationException validationException => ValidationException validationException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = (int)validationException.StatusCode context.Response.StatusCode = (int)validationException.StatusCode
), ),
BadRequestException => BadRequestException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest context.Response.StatusCode = StatusCodes.Status400BadRequest
), ),
NotFoundException => NotFoundException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.4",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status404NotFound context.Response.StatusCode = StatusCodes.Status404NotFound
), ),
AppException => AppException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest context.Response.StatusCode = StatusCodes.Status400BadRequest
), ),
DbUpdateConcurrencyException => DbUpdateConcurrencyException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.8",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status409Conflict context.Response.StatusCode = StatusCodes.Status409Conflict
), ),
RpcException => RpcException =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest context.Response.StatusCode = StatusCodes.Status400BadRequest
), ),
_ => _ =>
( (
exceptionType.Message, exceptionType.Message,
"https://www.rfc-editor.org/rfc/rfc7231#section-6.6.1",
exceptionType.GetType().Name, exceptionType.GetType().Name,
context.Response.StatusCode = StatusCodes.Status500InternalServerError context.Response.StatusCode = StatusCodes.Status500InternalServerError
) )
}; };
await problemDetailsService.WriteAsync(new ProblemDetailsContext var problem = new ProblemDetailsContext
{ {
HttpContext = context, HttpContext = context,
ProblemDetails = ProblemDetails =
{ {
Title = details.Title, Title = details.Title,
Detail = details.Detail, Detail = details.Detail,
Type = details.Type,
Status = details.StatusCode Status = details.StatusCode
} }
}); };
if (env.IsDevelopment())
{
problem.ProblemDetails.Extensions.Add("exception", exceptionHandlerFeature?.Error.ToString());
}
await problemDetailsService.WriteAsync(problem);
} }
} }
}); });