.NET Framework 4.7.2中如何自动注入NLog请求作用域属性?
在.NET Framework 4.7.2中自动注入NLog作用域属性的方案
你之前在Global.asax的Application_BeginRequest中配置不生效,核心原因是没有维持NLog作用域的生命周期:PushScopeProperty返回的IDisposable实例必须被持有到请求结束,否则作用域会在方法执行完成后立即释放,日志中无法获取到这些属性。
下面提供两种可行的自动注入方案:
方案一:通过Global.asax管理请求生命周期
利用Application_BeginRequest创建作用域,Application_EndRequest释放作用域,通过HttpContext.Items存储作用域实例(保证每个请求独立):
protected void Application_BeginRequest(HttpContext context) { var req = context.Request; var scopes = new List<IDisposable>(); // 添加请求路径属性 scopes.Add(LogManager.GetCurrentClassLogger().PushScopeProperty("RequestEndpoint", req.Url.LocalPath)); // 按需添加请求头属性(判空避免空值) if (!string.IsNullOrEmpty(req.Headers["UserId"])) { scopes.Add(LogManager.GetCurrentClassLogger().PushScopeProperty("RequestUser", req.Headers["UserId"])); } if (!string.IsNullOrEmpty(req.Headers["FE_URL"])) { scopes.Add(LogManager.GetCurrentClassLogger().PushScopeProperty("FE_URL", req.Headers["FE_URL"])); } // 将作用域集合存入当前请求上下文 context.Items["NLogRequestScopes"] = scopes; } protected void Application_EndRequest(HttpContext context) { // 请求结束时释放所有作用域 if (context.Items["NLogRequestScopes"] is List<IDisposable> scopes) { foreach (var scope in scopes) { scope.Dispose(); } } }
方案二:使用全局Action过滤器(推荐)
针对Web API或MVC项目,通过自定义Action过滤器,在接口执行前后自动管理NLog作用域,更贴合业务请求流程:
1. Web API项目实现
自定义过滤器
public class NLogScopeActionFilter : ActionFilterAttribute { private readonly ILogger _logger = LogManager.GetCurrentClassLogger(); public override void OnActionExecuting(HttpActionContext actionContext) { var req = actionContext.Request; var scopes = new List<IDisposable>(); // 添加请求路径 scopes.Add(_logger.PushScopeProperty("RequestEndpoint", req.RequestUri.LocalPath)); // 读取请求头属性 if (req.Headers.Contains("UserId")) { var userId = req.Headers.GetValues("UserId").FirstOrDefault(); scopes.Add(_logger.PushScopeProperty("RequestUser", userId)); } if (req.Headers.Contains("FE_URL")) { var feUrl = req.Headers.GetValues("FE_URL").FirstOrDefault(); scopes.Add(_logger.PushScopeProperty("FE_URL", feUrl)); } // 存储作用域到请求属性 actionContext.Properties["NLogScopes"] = scopes; base.OnActionExecuting(actionContext); } public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { // 释放作用域 if (actionExecutedContext.ActionContext.Properties.TryGetValue("NLogScopes", out var scopesObj) && scopesObj is List<IDisposable> scopes) { foreach (var scope in scopes) { scope.Dispose(); } } base.OnActionExecuted(actionExecutedContext); } }
注册全局过滤器
在WebApiConfig.cs中添加:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // 注册NLog作用域过滤器 config.Filters.Add(new NLogScopeActionFilter()); // 其他Web API配置... } }
2. MVC项目实现
自定义过滤器
public class NLogScopeActionFilter : ActionFilterAttribute { private readonly ILogger _logger = LogManager.GetCurrentClassLogger(); public override void OnActionExecuting(ActionExecutingContext filterContext) { var req = filterContext.HttpContext.Request; var scopes = new List<IDisposable>(); scopes.Add(_logger.PushScopeProperty("RequestEndpoint", req.Url.LocalPath)); if (!string.IsNullOrEmpty(req.Headers["UserId"])) { scopes.Add(_logger.PushScopeProperty("RequestUser", req.Headers["UserId"])); } if (!string.IsNullOrEmpty(req.Headers["FE_URL"])) { scopes.Add(_logger.PushScopeProperty("FE_URL", req.Headers["FE_URL"])); } filterContext.HttpContext.Items["NLogScopes"] = scopes; base.OnActionExecuting(filterContext); } public override void OnActionExecuted(ActionExecutedContext filterContext) { if (filterContext.HttpContext.Items["NLogScopes"] is List<IDisposable> scopes) { foreach (var scope in scopes) { scope.Dispose(); } } base.OnActionExecuted(filterContext); } }
注册全局过滤器
在FilterConfig.cs中添加:
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new NLogScopeActionFilter()); // 其他MVC过滤器配置... } }
内容的提问来源于stack exchange,提问作者Nayeer Mahiuddin
相关产品推荐
相关产品推荐

