refactor: to return the result according to the RFC 7807 standard and add a traceId
This commit is contained in:
		@@ -1,10 +1,13 @@
 | 
			
		||||
using FluentValidation;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Mirea.Api.DataAccess.Application.Common.Exceptions;
 | 
			
		||||
using Mirea.Api.Dto.Responses;
 | 
			
		||||
using Mirea.Api.Endpoint.Common.Exceptions;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Security;
 | 
			
		||||
using System.Text.Json;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
@@ -27,50 +30,55 @@ public class CustomExceptionHandlerMiddleware(RequestDelegate next, ILogger<Cust
 | 
			
		||||
 | 
			
		||||
    private Task HandleExceptionAsync(HttpContext context, Exception exception)
 | 
			
		||||
    {
 | 
			
		||||
        var code = StatusCodes.Status500InternalServerError;
 | 
			
		||||
        var result = string.Empty;
 | 
			
		||||
        var traceId = Activity.Current?.Id ?? context.TraceIdentifier;
 | 
			
		||||
 | 
			
		||||
        var problemDetails = new ProblemDetails
 | 
			
		||||
        {
 | 
			
		||||
            Type = "https://tools.ietf.org/html/rfc9110#section-15.6",
 | 
			
		||||
            Title = "An unexpected error occurred.",
 | 
			
		||||
            Status = StatusCodes.Status500InternalServerError,
 | 
			
		||||
            Detail = exception.Message,
 | 
			
		||||
            Extensions = new Dictionary<string, object?>()
 | 
			
		||||
            {
 | 
			
		||||
                { "traceId", traceId }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        switch (exception)
 | 
			
		||||
        {
 | 
			
		||||
            case ValidationException validationException:
 | 
			
		||||
                code = StatusCodes.Status400BadRequest;
 | 
			
		||||
                result = JsonSerializer.Serialize(new ErrorResponse()
 | 
			
		||||
                problemDetails.Status = StatusCodes.Status400BadRequest;
 | 
			
		||||
                problemDetails.Type = "https://tools.ietf.org/html/rfc9110#section-15.5.1";
 | 
			
		||||
                problemDetails.Title = "Validation errors occurred.";
 | 
			
		||||
                problemDetails.Extensions = new Dictionary<string, object?>
 | 
			
		||||
                {
 | 
			
		||||
                    Error = validationException.Message,
 | 
			
		||||
                    Code = code
 | 
			
		||||
                });
 | 
			
		||||
                    { "errors", validationException.Errors.Select(e => e.ErrorMessage).ToArray() },
 | 
			
		||||
                    { "traceId", traceId }
 | 
			
		||||
                };
 | 
			
		||||
                break;
 | 
			
		||||
            case NotFoundException:
 | 
			
		||||
                code = StatusCodes.Status404NotFound;
 | 
			
		||||
                problemDetails.Status = StatusCodes.Status404NotFound;
 | 
			
		||||
                problemDetails.Type = "https://tools.ietf.org/html/rfc9110#section-15.5.4";
 | 
			
		||||
                problemDetails.Title = "Resource not found.";
 | 
			
		||||
                break;
 | 
			
		||||
            case ControllerArgumentException:
 | 
			
		||||
                code = StatusCodes.Status400BadRequest;
 | 
			
		||||
                problemDetails.Status = StatusCodes.Status400BadRequest;
 | 
			
		||||
                problemDetails.Type = "https://tools.ietf.org/html/rfc9110#section-15.5.1";
 | 
			
		||||
                problemDetails.Title = "Invalid arguments provided.";
 | 
			
		||||
                break;
 | 
			
		||||
            case SecurityException:
 | 
			
		||||
                code = StatusCodes.Status401Unauthorized;
 | 
			
		||||
                problemDetails.Status = StatusCodes.Status401Unauthorized;
 | 
			
		||||
                problemDetails.Type = "https://tools.ietf.org/html/rfc9110#section-15.5.2";
 | 
			
		||||
                problemDetails.Title = "Unauthorized access.";
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        context.Response.ContentType = "application/json";
 | 
			
		||||
        context.Response.StatusCode = code;
 | 
			
		||||
 | 
			
		||||
        if (!string.IsNullOrEmpty(result))
 | 
			
		||||
            return context.Response.WriteAsync(result);
 | 
			
		||||
 | 
			
		||||
        string error;
 | 
			
		||||
        if (code == StatusCodes.Status500InternalServerError)
 | 
			
		||||
        {
 | 
			
		||||
            error = "Internal Server Error";
 | 
			
		||||
        if (problemDetails.Status == StatusCodes.Status500InternalServerError)
 | 
			
		||||
            logger.LogError(exception, "Internal server error when processing the request");
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            error = exception.Message;
 | 
			
		||||
 | 
			
		||||
        result = JsonSerializer.Serialize(new ErrorResponse()
 | 
			
		||||
        {
 | 
			
		||||
            Error = error,
 | 
			
		||||
            Code = code
 | 
			
		||||
        });
 | 
			
		||||
        context.Response.ContentType = "application/json";
 | 
			
		||||
        context.Response.StatusCode = problemDetails.Status.Value;
 | 
			
		||||
 | 
			
		||||
        return context.Response.WriteAsync(result);
 | 
			
		||||
        return context.Response.WriteAsync(JsonSerializer.Serialize(problemDetails));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -4,9 +4,11 @@ using Microsoft.Extensions.Hosting;
 | 
			
		||||
using Mirea.Api.Endpoint.Common.Services;
 | 
			
		||||
using Mirea.Api.Endpoint.Configuration.Model;
 | 
			
		||||
using Serilog;
 | 
			
		||||
using Serilog.Context;
 | 
			
		||||
using Serilog.Events;
 | 
			
		||||
using Serilog.Filters;
 | 
			
		||||
using Serilog.Formatting.Compact;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.IO;
 | 
			
		||||
 | 
			
		||||
namespace Mirea.Api.Endpoint.Configuration.Core.Startup;
 | 
			
		||||
@@ -55,7 +57,14 @@ public static class LoggerConfiguration
 | 
			
		||||
 | 
			
		||||
    public static IApplicationBuilder UseCustomSerilog(this IApplicationBuilder app)
 | 
			
		||||
    {
 | 
			
		||||
        return app.UseSerilogRequestLogging(options =>
 | 
			
		||||
        return app.Use(async (context, next) =>
 | 
			
		||||
        {
 | 
			
		||||
            var traceId = Activity.Current?.Id ?? context.TraceIdentifier;
 | 
			
		||||
            using (LogContext.PushProperty("TraceId", traceId))
 | 
			
		||||
            {
 | 
			
		||||
                await next();
 | 
			
		||||
            }
 | 
			
		||||
        }).UseSerilogRequestLogging(options =>
 | 
			
		||||
        {
 | 
			
		||||
            options.MessageTemplate = "[{RequestMethod}] {RequestPath} [Client {RemoteIPAddress}] [{StatusCode}] in {Elapsed:0.0000} ms";
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user