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

.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 05:20:50