ASP.NET Core如何获取异常来源控制器的ControllerContext实例
实现方案
UseExceptionHandler 触发错误处理逻辑时,会复用原有HttpContext对象重新走一遍请求管道到ErrorController,原始请求执行到异常Controller时生成的ControllerContext不会被默认持久化,需要在MVC执行阶段提前把上下文存下来,异常处理时直接读取即可。
步骤1:添加全局过滤器捕获原始Controller上下文
新增一个Action过滤器,在请求进入任意Controller的Action执行前,把当前的Controller实例/ControllerContext存入HttpContext的Items字典(这个字典在同一次请求的整个生命周期,包括异常重处理阶段都不会丢失):
public class StoreOriginalControllerContextFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { // 存储当前Controller实例,后续可直接通过它拿到ControllerContext context.HttpContext.Items["__OriginalController"] = context.Controller; } public void OnActionExecuted(ActionExecutedContext context) { // 无需处理执行完成逻辑 } }
在Startup.ConfigureServices中注册这个全局过滤器,保证所有Action执行前都会触发存储逻辑:
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { options.Filters.Add<StoreOriginalControllerContextFilter>(); // 其他原有MVC配置 }); // 其他服务注册逻辑 }
步骤2:在错误控制器中读取原始上下文
修改ErrorController的Index逻辑,从HttpContext.Items中取出之前存储的原始Controller实例,即可拿到对应的ControllerContext:
public class ErrorController : Controller { public IActionResult Index() { var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>(); if (exceptionFeature == null || exceptionFeature.Error == null) { // 原代码漏了throw关键字,这里已修正 throw new Exception("Please configure app.UseExceptionHandler(\"/Error/Index\");"); } // 读取原始抛出异常的Controller实例 if (HttpContext.Items.TryGetValue("__OriginalController", out var storedValue) && storedValue is ControllerBase originalController) { // 这里拿到的就是抛异常的TestController实例,它的ControllerContext就是你要的原始上下文 ControllerContext originalContext = originalController.ControllerContext; // 可按需读取原始上下文的路由数据、请求参数、ModelState等信息 var originalRouteData = originalContext.RouteData; var originalModelState = originalContext.ModelState; } return View(); } }
注意事项
- 该方案仅对进入MVC Controller执行阶段后抛出的异常有效,如果异常发生在MVC中间件之前(比如其他自定义中间件报错、静态文件处理阶段报错、路由匹配失败),不会生成ControllerContext,Items中自然也拿不到对应值,符合正常逻辑。
IExceptionHandlerPathFeature仅会记录异常对象、异常发生的请求路径,不会持有MVC执行阶段的上下文对象,无法直接从这个特性里拿到原始ControllerContext。
内容的提问来源于stack exchange,提问作者LHA
相关产品推荐
相关产品推荐

