首页 > 解决方案 > 使用通用响应模型找不到路由异常

问题描述

我试图在找不到路由时捕获异常,并使用通用响应模型包装异常。

正如问题的答案中所给出的,我尝试实施,但这个解决方案似乎也不适用于我的用例。

因为在没有找到资源时也会在响应中添加状态码 404,例如 when Id is not found

 app.UseStatusCodePages(new StatusCodePagesOptions()
 {
     HandleAsync = (ctx) =>
     {
          if (ctx.HttpContext.Response.StatusCode == 404)
          {
                throw new RouteNotFoundException("Route not found");
          }

          return Task.FromResult(0);
     }
 })

RouteNotFoundException

public class RouteNotFoundException : Exception
{
    public RouteNotFoundException()
          : base()
    {
    }

    public RouteNotFoundException(string message)
        : base(message)
    {
    }
}

ApiExceptionFilterAttribute

public class ApiExceptionFilterAttribute : ExceptionFilterAttribute
{
        private readonly IDictionary<Type, Action<ExceptionContext>> _exceptionHandlers;

        public ApiExceptionFilterAttribute()
        {
            // Register known exception types and handlers.
            _exceptionHandlers = new Dictionary<Type, Action<ExceptionContext>>
            {
                { typeof(RouteNotFoundException), HandleNotFoundException }
            };
        }
        public override void OnException(ExceptionContext context)
        {
            HandleException(context);

            base.OnException(context);
        }
        private void HandleException(ExceptionContext context)
        {
            Type type = context.Exception.GetType();
            if (_exceptionHandlers.ContainsKey(type))
            {
                _exceptionHandlers[type].Invoke(context);
                return;
            }

            HandleUnknownException(context);
        }
        private void HandleNotFoundException(ExceptionContext context)
        {
            var exception = context.Exception as RouteNotFoundException;

            var details = new ProblemDetails()
            {
                Type = "https://tools.ietf.org/html/rfc7231#section-6.5.4",
                Title = "The specified resource was not found.",
                Detail = exception.Message
            };

            context.Result = new NotFoundObjectResult(details);
            context.ExceptionHandled = true;
        }
        private void HandleUnknownException(ExceptionContext context)
        {
            var details = new ProblemDetails
            {
                Status = StatusCodes.Status500InternalServerError,
                Title = "An error occurred while processing your request.",
                Type = "https://tools.ietf.org/html/rfc7231#section-6.6.1"
            };

            context.Result = new ObjectResult(details)
            {
                StatusCode = StatusCodes.Status500InternalServerError
            };

            context.ExceptionHandled = true;
        }
}

ResponseWrapper 中间件

public class ResponseWrapperMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<ResponseWrapperMiddleware> _logger;

    public ResponseWrapperMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
    {
        _next = next ?? throw new ArgumentNullException(nameof(next));
        _logger = loggerFactory?.CreateLogger<ResponseWrapperMiddleware>() ?? throw new ArgumentNullException(nameof(loggerFactory));
    }

    public async Task Invoke(HttpContext httpContext)
    {

        try
        {
            var currentBody = httpContext.Response.Body;

            using (var memoryStream = new MemoryStream())
            {
                //set the current response to the memorystream.
                httpContext.Response.Body = memoryStream;

                await _next(httpContext);

                //reset the body 
                httpContext.Response.Body = currentBody;
                memoryStream.Seek(0, SeekOrigin.Begin);

                var readToEnd = new StreamReader(memoryStream).ReadToEnd();
                var objResult = JsonConvert.DeserializeObject(readToEnd);
                var result = CommonApiResponse.Create((HttpStatusCode)httpContext.Response.StatusCode, objResult, null);
                await httpContext.Response.WriteAsync(JsonConvert.SerializeObject(result));
            }
        }
        catch (Exception ex)
        {
            if (httpContext.Response.HasStarted)
            {
                _logger.LogWarning("The response has already started, the http status code middleware will not be executed.");
                throw;
            }
            return;
        }
    }
}

// Extension method used to add the middleware to the HTTP request pipeline.
public static class ResponseWrapperMiddlewareExtensions
{
    public static IApplicationBuilder UseResponseWrapperMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<ResponseWrapperMiddleware>();
    }
}

通用响应模型

public class CommonApiResponse
{
    public static CommonApiResponse Create(HttpStatusCode statusCode, object result = null, string errorMessage = null)
    {
        return new CommonApiResponse(statusCode, result, errorMessage);
    }

    public string Version => "1.2.3";

    public int StatusCode { get; set; }
    public string RequestId { get; }

    public string ErrorMessage { get; set; }

    public object Result { get; set; }

    protected CommonApiResponse(HttpStatusCode statusCode, object result = null, string errorMessage = null)
    {
        RequestId = Guid.NewGuid().ToString();
        StatusCode = (int)statusCode;
        Result = result;
        ErrorMessage = errorMessage;
    }
}

如果找不到路由并捕获通用模型中的错误,如何处理错误?这种情况的解决方法是什么?

标签: c#.net-coreasp.net-core-5.0

解决方案


推荐阅读