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

在C# ASP.NET Core中如何将中间件捕获的异常重定向回控制器方法?

问题分析与解决方案

你遇到的核心问题是重定向会触发浏览器发起全新的HTTP请求,原请求的HttpContext.Features不会被携带到新请求中,因此ExceptionManagerController拿到的是新请求的HttpContext,自然找不到你设置的IExceptionHttpContextFeature。

以下是几种可行的解决思路:


方案1:用Session传递异常信息

Session适合跨请求传递数据,能满足重定向场景的需求。注意直接存储Exception对象可能存在序列化问题,建议存储异常的关键信息,或让自定义异常实现ISerializable接口。

修改中间件代码

public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
{
    if (exception != null)
    {
        Logger.LogError($"Erro na solicitação do usuário {httpContext.User.Identity.Name}. Error Message: {exception.Message}, Time of occurrence {DateTime.UtcNow}");
        
        // 将异常关键信息存入Session
        httpContext.Session.SetString("ExceptionMessage", exception.Message);
        httpContext.Session.SetString("ExceptionType", exception.GetType().FullName);
        
        httpContext.Response.Redirect("/GestorDeExcecoes/Index");
    }
    return true;
}

修改控制器代码

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public async Task<IActionResult> Index()
{
    var exceptionMessage = HttpContext.Session.GetString("ExceptionMessage");
    var exceptionType = HttpContext.Session.GetString("ExceptionType");

    if (string.IsNullOrEmpty(exceptionMessage))
    {
        return RedirectToAction("Index", "Home");
    }
    else
    {
        // 构建视图模型,可根据类型自定义处理逻辑
        var vm = new GlobalExceptionVM(new Exception(exceptionMessage)
        {
            Source = exceptionType
        });
        
        // 清理Session,避免重复读取
        HttpContext.Session.Remove("ExceptionMessage");
        HttpContext.Session.Remove("ExceptionType");
        
        return View(vm);
    }
}

启用Session

需要在Program.cs中注册并启用Session:

builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(1); // 设置过期时间
    options.Cookie.IsEssential = true;
});

// ...

app.UseSession();

方案2:直接返回错误视图(无需重定向)

如果不需要跳转URL,直接在中间件中调用错误视图,复用同一个HttpContext,就能正常读取到你设置的Feature。

修改中间件代码

private readonly IServiceProvider _serviceProvider;

public GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger, IServiceProvider serviceProvider)
{
    Logger = logger;
    _serviceProvider = serviceProvider;
}

public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
{
    if (exception != null)
    {
        Logger.LogError($"Erro na solicitação do usuário {httpContext.User.Identity.Name}. Error Message: {exception.Message}, Time of occurrence {DateTime.UtcNow}");
        
        // 设置Feature
        httpContext.Features.Set<IExceptionHttpContextFeature>(new ExceptionHttpContextFeature(exception));
        
        // 获取控制器实例并调用视图
        var controller = _serviceProvider.GetRequiredService<ExceptionManagerController>();
        controller.ControllerContext = new ControllerContext
        {
            HttpContext = httpContext
        };
        
        var result = await controller.Index();
        await result.ExecuteResultAsync(controller.ControllerContext);
    }
    return true;
}

方案3:用加密Cookie传递关键信息

如果需要跨请求传递少量数据,可以将异常信息加密后存入Cookie,控制器读取后立即删除Cookie。这种方式适合存储简短的异常描述,不适合传递完整异常对象。


额外优化建议

  1. 移除ExceptionHttpContextFeature的无参构造函数,强制传入异常,避免空引用:
public class ExceptionHttpContextFeature: IExceptionHttpContextFeature
{
    public Exception Exception { get; }

    public ExceptionHttpContextFeature(Exception exception)
    {
        Exception = exception ?? throw new ArgumentNullException(nameof(exception));
    }
}
  1. 确保IExceptionHandler已正确注册到DI容器:
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
app.UseExceptionHandler(); // 启用异常处理中间件

内容的提问来源于stack exchange,提问作者Philipe Riskalla Leal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 11:07:45