【问题标题】:.Net Core: Return IActionResult from a custom Exception Middleware.Net Core:从自定义异常中间件返回 IActionResult
【发布时间】:2020-04-05 05:25:13
【问题描述】:

我在我的 .Net Core 应用程序中创建了一个新的异常中间件。整个应用程序中的所有异常都在此处捕获和记录。我想要的是从异常中间件返回一个像 InternalServerError() 或 NotFound() 这样的 IActionResult 类型,而不是像下面那样做 response.WriteAsync。

控制器方法:

   public async Task<IActionResult> Post()
    {
        //Do Something
        return Ok();
    }

中间件:

public class ExceptionMiddleware
    {
        private readonly RequestDelegate _next;
        public ExceptionMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _next.Invoke(context);
            }
            catch (Exception ex)
            {
                await HandleExceptionAsync(context, ex);
            }
        }

        private async Task HandleExceptionAsync(HttpContext context, Exception exception)
        {
            var response = context.Response;
            var statusCode = (int)HttpStatusCode.InternalServerError;
            var message = exception.Message;
            var description = exception.Message;

            response.ContentType = "application/json";
            response.StatusCode = statusCode;

            await response.WriteAsync(JsonConvert.SerializeObject(new ErrorResponse
            {
                Message = message,
                Description = description
            }));
        }
    }

【问题讨论】:

    标签: c# .net asp.net-mvc asp.net-core .net-core


    【解决方案1】:

    IActionResult 是来自 MVC 的东西,因此它仅在 MVC 管道(包括 Razor 页面)中可用。就在 MVC 中间件终止之前,它将使用ExecuteAsync执行这些操作结果。然后该方法负责将该响应写入HttpContext.Response

    因此,在自定义中间件中,您不能只设置操作结果并执行它,因为您不在 MVC 管道中运行。但是,有了这些知识,您就可以简单地自己执行结果。

    假设您要执行NotFoundResult,这是Controller.NotFound() 创建的。因此,您创建该结果并使用 .该执行器将能够执行该结果对象并写入响应:

    var result = new NotFoundResult();
    await result.ExecuteAsync(new ActionContext
    {
        HttpContext = context,
    });
    

    【讨论】:

      【解决方案2】:

      这实际上是不可能的,因为IActionResult 和中间件在架构中彼此相关。中间件的位置要低得多,因此它无法在堆栈中进一步到达IActionResult。这是一个更多地谈论它的答案:https://stackoverflow.com/a/43111292/12431728

      【讨论】:

        【解决方案3】:

        只需添加以下行即可完成您想要做的事情:

        app.UseStatusCodePagesWithReExecute("/Public/Error", "?statusCode={0}");
        

        到 Startup.cs 中的 Configure 方法。然后,您可以使用执行以下操作的 Error 方法创建您的公共控制器:

        [AllowAnonymous]
        public IActionResult Error(int? statusCode = null)
        {
            // Retrieve error information in case of internal errors.
            var error = HttpContext.Features.Get<IExceptionHandlerFeature>()?.Error;
            var path = HttpContext.Features.Get<IExceptionHandlerPathFeature>()?.Path;
        
            // TODO: Redirect here based on your status code or perhaps just render different views for different status codes.
        }
        

        还有另一个中间件可以让你做类似的事情:

        app.UseStatusCodePages(async context =>
        {
            if (context.HttpContext.Response.StatusCode == 401)
            {
                context.HttpContext.Response.Redirect("Errors/Unauthorized/");
            }
            else if (context.HttpContext.Response.StatusCode == 500)
            {
                // TODO: Redirect for 500 and so on...
            }
         });
        

        【讨论】:

          猜你喜欢
          • 2019-06-30
          • 2019-11-10
          • 1970-01-01
          • 1970-01-01
          • 2021-07-13
          • 1970-01-01
          • 2019-01-24
          • 1970-01-01
          • 2019-04-04
          相关资源
          最近更新 更多