如何在ASP.NET Core MVC中将异常从中间件传递至ErrorController
你遇到的问题核心是重定向会触发新的HTTP请求,原来请求的HttpContext.Items仅在当前请求周期内有效,新请求无法访问旧请求的Items数据,所以传递失败。以下是几种可行的解决方案:
方案1:使用TempData跨请求传递异常
TempData专门用于跨请求保存数据(默认基于Session或Cookie实现),适合在重定向场景下传递异常信息。
修改全局异常中间件
需要注入ITempDataDictionaryFactory来创建TempData实例:
public class GlobalExceptionHandlingMiddleware { private readonly RequestDelegate _next; private readonly ITempDataDictionaryFactory _tempDataFactory; public GlobalExceptionHandlingMiddleware(RequestDelegate next, ITempDataDictionaryFactory tempDataFactory) { _next = next; _tempDataFactory = tempDataFactory; } public async Task Invoke(HttpContext httpContext) { try { await _next(httpContext); } catch (Exception ex) { await HandleExceptionAsync(httpContext, ex); } } private async Task HandleExceptionAsync(HttpContext httpContext, Exception ex) { var tempData = _tempDataFactory.GetTempData(httpContext); tempData["exception"] = ex; httpContext.Response.Redirect("/Error/Error"); } }
修改ErrorController
从TempData中取出异常:
public class ErrorController : Controller { private readonly ILogger<ErrorController> _logger; public ErrorController(ILogger<ErrorController> logger) { _logger = logger; } [Route("/Error/Error")] public IActionResult Error() { if (TempData.TryGetValue("exception", out var exceptionObj) && exceptionObj is Exception ex) { ViewData["message"] = ex.Message; _logger.LogError(ex, "Internal server error"); } return View("Error"); } }
方案2:直接在中间件返回错误视图(无需重定向)
这种方式不发起新请求,直接在当前请求上下文返回Error视图,HttpContext.Items可以正常传递:
修改中间件的HandleExceptionAsync方法
private async Task HandleExceptionAsync(HttpContext httpContext, Exception ex, IViewEngine viewEngine, ILogger<ErrorController> logger) { httpContext.Items["exception"] = ex; httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError; httpContext.Response.ContentType = "text/html"; // 构建路由数据与Action上下文 var routeData = new RouteData(); routeData.Values.Add("controller", "Error"); routeData.Values.Add("action", "Error"); var actionContext = new ActionContext(httpContext, routeData, new ControllerActionDescriptor()); // 实例化ErrorController并获取视图结果 var controller = new ErrorController(logger); var viewResult = controller.Error() as ViewResult; if (viewResult != null) { var viewEngineResult = viewEngine.FindView(actionContext, viewResult.ViewName, false); if (viewEngineResult.Success) { await viewEngineResult.View.RenderAsync(new ViewContext(actionContext, viewEngineResult.View, viewResult.ViewData, viewResult.TempData, httpContext.Response.Body)); } } }
注意:需要在中间件构造函数中注入
IViewEngine和ILogger<ErrorController>,避免手动实例化控制器时缺失依赖。
方案3:使用ASP.NET Core内置异常处理中间件(推荐)
官方内置的UseExceptionHandler中间件已经封装了异常处理逻辑,无需自定义全局中间件,配置后可直接将异常传递到ErrorController:
在Program.cs中配置
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllersWithViews(); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run();
修改ErrorController获取异常
通过IExceptionHandlerPathFeature获取异常信息:
public class ErrorController : Controller { private readonly ILogger<ErrorController> _logger; public ErrorController(ILogger<ErrorController> logger) { _logger = logger; } [Route("/Error/Error")] public IActionResult Error() { var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>(); if (exceptionFeature != null) { Exception ex = exceptionFeature.Error; ViewData["message"] = ex.Message; _logger.LogError(ex, "Internal server error"); } return View("Error"); } }
内容的提问来源于stack exchange,提问作者JagathNalin
相关产品推荐
相关产品推荐

