using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Net;
namespace BankSampahApp.Filters;
///
/// Global exception filter untuk menangani error secara terpusat
///
public class GlobalExceptionFilter : IExceptionFilter
{
private readonly ILogger _logger;
private readonly IWebHostEnvironment _environment;
///
/// Constructor dengan dependency injection
///
/// Logger untuk logging
/// Environment information
public GlobalExceptionFilter(
ILogger logger,
IWebHostEnvironment environment)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_environment = environment ?? throw new ArgumentNullException(nameof(environment));
}
///
/// Handle exception yang terjadi di aplikasi
///
/// Exception context
public void OnException(ExceptionContext context)
{
var exception = context.Exception;
var requestId = context.HttpContext.TraceIdentifier;
// Log the exception with details
_logger.LogError(exception,
"Unhandled exception occurred. RequestId: {RequestId}, Path: {Path}, Method: {Method}, User: {User}",
requestId,
context.HttpContext.Request.Path,
context.HttpContext.Request.Method,
context.HttpContext.User?.Identity?.Name ?? "Anonymous");
// Determine response based on request type
if (IsApiRequest(context.HttpContext.Request))
{
HandleApiException(context, exception, requestId);
}
else
{
HandleWebException(context, exception, requestId);
}
}
///
/// Handle exception untuk API requests
///
/// Exception context
/// Exception yang terjadi
/// Request ID
private void HandleApiException(ExceptionContext context, Exception exception, string requestId)
{
var statusCode = GetStatusCodeFromException(exception);
var includeDetails = _environment.IsDevelopment();
var response = new
{
Error = new
{
Message = includeDetails ? exception.Message : "An error occurred while processing your request.",
RequestId = requestId,
Details = includeDetails ? exception.ToString() : null,
Type = exception.GetType().Name,
Timestamp = DateTime.UtcNow
}
};
context.Result = new JsonResult(response)
{
StatusCode = (int)statusCode
};
context.ExceptionHandled = true;
}
///
/// Handle exception untuk Web requests
///
/// Exception context
/// Exception yang terjadi
/// Request ID
private void HandleWebException(ExceptionContext context, Exception exception, string requestId)
{
var statusCode = GetStatusCodeFromException(exception);
// Set status code
context.HttpContext.Response.StatusCode = (int)statusCode;
// Store exception details untuk error page
context.HttpContext.Items["Exception"] = exception;
context.HttpContext.Items["RequestId"] = requestId;
// Redirect to error page
var routeData = new RouteData();
routeData.Values["controller"] = "Home";
routeData.Values["action"] = "Error";
context.Result = new RedirectToRouteResult(routeData);
context.ExceptionHandled = true;
}
///
/// Determine HTTP status code based on exception type
///
/// Exception
/// HTTP status code
private static HttpStatusCode GetStatusCodeFromException(Exception exception)
{
return exception switch
{
ArgumentNullException => HttpStatusCode.BadRequest,
ArgumentException => HttpStatusCode.BadRequest,
UnauthorizedAccessException => HttpStatusCode.Unauthorized,
NotImplementedException => HttpStatusCode.NotImplemented,
TimeoutException => HttpStatusCode.RequestTimeout,
_ => HttpStatusCode.InternalServerError
};
}
///
/// Check if request is API request
///
/// HTTP request
/// True if API request
private static bool IsApiRequest(HttpRequest request)
{
// Check if request accepts JSON or has API path
return request.Headers["Accept"].ToString().Contains("application/json") ||
request.Path.StartsWithSegments("/api") ||
request.Path.StartsWithSegments("/health");
}
}