.Net Core:从自定义异常中间件返回 IActionResult

Posted

技术标签:

【中文标题】.Net Core:从自定义异常中间件返回 IActionResult【英文标题】:.Net Core: Return IActionResult from a custom Exception Middleware 【发布时间】: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
            ));
        
    

【问题讨论】:

【参考方案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://***.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...
    
 );

【讨论】:

以上是关于.Net Core:从自定义异常中间件返回 IActionResult的主要内容,如果未能解决你的问题,请参考以下文章

asp.net core 自定义异常处理中间件

一文了解.Net Core 3.1 Web API基础知识

为啥 Core Data 获取请求从自定义 UITableViewCell 返回空?

Laravel:从自定义中间件油门组返回 bool

如何通过 Asp.Net Core 中间件的 JsonResult 响应?

使用中间件的全局异常处理在 ASP.Net Core 应用程序中不起作用