Skip to content

Commit

Permalink
(#217) [Asp.Net Core 8] IExceptionHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
phongnguyend committed Dec 30, 2023
1 parent 128b6fe commit d800f1e
Show file tree
Hide file tree
Showing 17 changed files with 445 additions and 326 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using ClassifiedAds.CrossCuttingConcerns.Exceptions;
using ClassifiedAds.Infrastructure.Logging;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Diagnostics;
using System.Net;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

namespace ClassifiedAds.Infrastructure.Web.ExceptionHandlers;

public class GlobalExceptionHandler : IExceptionHandler
{
private readonly ILogger<GlobalExceptionHandler> _logger;
private readonly GlobalExceptionHandlerOptions _options;

public GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger, IOptions<GlobalExceptionHandlerOptions> options)
{
_logger = logger;
_options = options.Value;
}

public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
{
var response = httpContext.Response;

if (exception is NotFoundException)
{
var problemDetails = new ProblemDetails
{
Detail = exception.Message,
Instance = null,
Status = (int)HttpStatusCode.NotFound,
Title = "Not Found",
Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4"
};

problemDetails.Extensions.Add("message", exception.Message);
problemDetails.Extensions.Add("traceId", Activity.Current.GetTraceId());

response.ContentType = "application/problem+json";
response.StatusCode = problemDetails.Status.Value;

var result = JsonSerializer.Serialize(problemDetails);
await response.WriteAsync(result, cancellationToken: cancellationToken);

return true;
}
else if (exception is ValidationException)
{
var problemDetails = new ProblemDetails
{
Detail = exception.Message,
Instance = null,
Status = (int)HttpStatusCode.BadRequest,
Title = "Bad Request",
Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1"
};

problemDetails.Extensions.Add("message", exception.Message);
problemDetails.Extensions.Add("traceId", Activity.Current.GetTraceId());

response.ContentType = "application/problem+json";
response.StatusCode = problemDetails.Status.Value;

var result = JsonSerializer.Serialize(problemDetails);
await response.WriteAsync(result, cancellationToken: cancellationToken);

return true;
}
else
{
_logger.LogError(exception, "[{Ticks}-{ThreadId}]", DateTime.UtcNow.Ticks, Environment.CurrentManagedThreadId);

if (_options.DetailLevel == GlobalExceptionDetailLevel.Throw)
{
return false;
}

var problemDetails = new ProblemDetails
{
Detail = _options.GetErrorMessage(exception),
Instance = null,
Status = (int)HttpStatusCode.InternalServerError,
Title = "Internal Server Error",
Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.6.1"
};

problemDetails.Extensions.Add("message", _options.GetErrorMessage(exception));
problemDetails.Extensions.Add("traceId", Activity.Current.GetTraceId());

response.ContentType = "application/problem+json";
response.StatusCode = problemDetails.Status.Value;

var result = JsonSerializer.Serialize(problemDetails);
await response.WriteAsync(result, cancellationToken: cancellationToken);

return true;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;

namespace ClassifiedAds.Infrastructure.Web.ExceptionHandlers;

public class GlobalExceptionHandlerOptions
{
public GlobalExceptionDetailLevel DetailLevel { get; set; }

public string GetErrorMessage(Exception ex)
{
return DetailLevel switch
{
GlobalExceptionDetailLevel.None => "An internal exception has occurred.",
GlobalExceptionDetailLevel.Message => ex.Message,
GlobalExceptionDetailLevel.StackTrace => ex.StackTrace,
GlobalExceptionDetailLevel.ToString => ex.ToString(),
_ => "An internal exception has occurred.",
};
}
}

public enum GlobalExceptionDetailLevel
{
None,
Message,
StackTrace,
ToString,
Throw,
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using ClassifiedAds.Infrastructure.Logging;
using ClassifiedAds.Infrastructure.Monitoring;
using ClassifiedAds.Infrastructure.Web.Filters;
using ClassifiedAds.Infrastructure.Web.ExceptionHandlers;
using ClassifiedAds.Services.AuditLog.ConfigurationOptions;
using ClassifiedAds.Services.AuditLog.RateLimiterPolicies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
Expand Down Expand Up @@ -36,9 +36,10 @@

services.AddMonitoringServices(appSettings.Monitoring);

services.AddExceptionHandler<GlobalExceptionHandler>();

services.AddControllers(configure =>
{
configure.Filters.Add(typeof(GlobalExceptionFilter));
})
.ConfigureApiBehaviorOptions(options =>
{
Expand Down Expand Up @@ -195,6 +196,8 @@
app.UseDeveloperExceptionPage();
}

app.UseExceptionHandler(options => { });

app.UseRouting();

app.UseCloudEvents();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using ClassifiedAds.Infrastructure.Logging;
using ClassifiedAds.Infrastructure.Monitoring;
using ClassifiedAds.Infrastructure.Web.Filters;
using ClassifiedAds.Infrastructure.Web.ExceptionHandlers;
using ClassifiedAds.Services.Configuration.ConfigurationOptions;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
Expand Down Expand Up @@ -36,9 +36,10 @@

services.AddMonitoringServices(appSettings.Monitoring);

services.AddExceptionHandler<GlobalExceptionHandler>();

services.AddControllers(configure =>
{
configure.Filters.Add(typeof(GlobalExceptionFilter));
})
.ConfigureApiBehaviorOptions(options =>
{
Expand Down Expand Up @@ -186,6 +187,8 @@
app.UseDeveloperExceptionPage();
}

app.UseExceptionHandler(options => { });

app.UseRouting();

app.UseCors("AllowAnyOrigin");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using ClassifiedAds.Infrastructure.Logging;
using ClassifiedAds.Infrastructure.Monitoring;
using ClassifiedAds.Infrastructure.Web.Filters;
using ClassifiedAds.Infrastructure.Web.ExceptionHandlers;
using ClassifiedAds.Services.Identity.ConfigurationOptions;
using ClassifiedAds.Services.Identity.Repositories;
using Microsoft.AspNetCore.Authentication.JwtBearer;
Expand Down Expand Up @@ -37,9 +37,10 @@

services.AddMonitoringServices(appSettings.Monitoring);

services.AddExceptionHandler<GlobalExceptionHandler>();

services.AddControllers(configure =>
{
configure.Filters.Add(typeof(GlobalExceptionFilter));
})
.ConfigureApiBehaviorOptions(options =>
{
Expand Down Expand Up @@ -194,6 +195,8 @@
app.UseDeveloperExceptionPage();
}

app.UseExceptionHandler(options => { });

app.UseRouting();

app.UseCors("AllowAnyOrigin");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using ClassifiedAds.Infrastructure.Logging;
using ClassifiedAds.Infrastructure.Monitoring;
using ClassifiedAds.Infrastructure.Web.Filters;
using ClassifiedAds.Infrastructure.Web.ExceptionHandlers;
using ClassifiedAds.Services.Notification.ConfigurationOptions;
using ClassifiedAds.Services.Notification.HostedServices;
using ClassifiedAds.Services.Notification.Hubs;
Expand Down Expand Up @@ -36,9 +36,10 @@

services.AddMonitoringServices(appSettings.Monitoring);

services.AddExceptionHandler<GlobalExceptionHandler>();

services.AddControllers(configure =>
{
configure.Filters.Add(typeof(GlobalExceptionFilter));
})
.ConfigureApiBehaviorOptions(options =>
{
Expand Down Expand Up @@ -196,6 +197,8 @@
app.UseDeveloperExceptionPage();
}

app.UseExceptionHandler(options => { });

app.UseRouting();

app.UseCors("AllowAnyOrigin");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using ClassifiedAds.Infrastructure.Logging;
using ClassifiedAds.Infrastructure.Monitoring;
using ClassifiedAds.Infrastructure.Web.Filters;
using ClassifiedAds.Infrastructure.Web.ExceptionHandlers;
using ClassifiedAds.Infrastructure.Web.MinimalApis;
using ClassifiedAds.Services.Product.ConfigurationOptions;
using ClassifiedAds.Services.Product.RateLimiterPolicies;
Expand Down Expand Up @@ -38,9 +38,10 @@

services.AddMonitoringServices(appSettings.Monitoring);

services.AddExceptionHandler<GlobalExceptionHandler>();

services.AddControllers(configure =>
{
configure.Filters.Add(typeof(GlobalExceptionFilter));
})
.ConfigureApiBehaviorOptions(options =>
{
Expand Down Expand Up @@ -208,6 +209,8 @@
app.UseDeveloperExceptionPage();
}

app.UseExceptionHandler(options => { });

app.UseRouting();

app.UseCors("AllowAnyOrigin");
Expand Down
Loading

0 comments on commit d800f1e

Please sign in to comment.