You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 09:01:29