如何访问ActionFilter内部属性并在控制器中使用其值
实现方案
你可以通过HttpContext.Items做单次请求内的参数传递,这是成本最低、最简洁的实现方式,同时先修正你原代码中User无上下文引用的小问题,完整实现如下:
第一步:修改LogAttribute代码,存入公共上下文
public class LogAttribute : ActionFilterAttribute { public LogAttribute(ILoggerFactory logger) { Logger = logger.CreateLogger<LogAttribute>(); } public ILogger Logger { get; } public override void OnActionExecuting(ActionExecutingContext context) { // 修正原代码的User引用错误,从当前请求上下文取用户信息 var userId = context.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier); var path = $"{context.HttpContext.Request.Path.Value}[{context.HttpContext.Request.Method}]"; Logger.LogDebug($"{path} started. User(id): {userId}."); // 存入HttpContext.Items,单次请求生命周期内全局可访问 context.HttpContext.Items["Log_UserId"] = userId; context.HttpContext.Items["Log_Path"] = path; } }
第二步:控制器中取值的两种用法
用法1:直接取值(无需额外封装)
只要控制器/对应Action加了[Log]特性,直接在任意位置读取即可:
[Log] public class HomeController : Controller { public IActionResult Index() { var userId = HttpContext.Items["Log_UserId"] as string; var path = HttpContext.Items["Log_Path"] as string; // 直接使用两个参数即可 return View(); } }
用法2:基类封装(更简洁,全局复用)
如果多个控制器都要用到这两个参数,可以封装到控制器基类里,直接当属性调用:
// 统一封装基类 public class BaseController : Controller { protected string LogUserId => HttpContext.Items["Log_UserId"] as string; protected string LogPath => HttpContext.Items["Log_Path"] as string; } // 业务控制器继承后直接使用 [Log] public class HomeController : BaseController { public IActionResult Index() { // 无需额外赋值,直接调用属性即可 var currentUserId = LogUserId; var currentPath = LogPath; return View(); } }
方案优势
- 实现成本极低,无需调整依赖注入规则
HttpContext.Items是ASP.NET Core内置的单次请求临时存储,不会出现跨请求串值、线程安全问题- 无额外性能开销,除了控制器外,同请求的中间件、其他过滤器也能读取这两个参数
内容的提问来源于stack exchange,提问作者Mister D
相关产品推荐
相关产品推荐

