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

如何在ASP.NET Core中从自定义NLog渲染器访问作用域服务?

解决思路与方案

你的问题核心是NLog渲染器创建的新作用域和WebAPI请求作用域相互独立,因此无法获取中间件已赋值的ApplicationContext。以下两种方案可以解决这个问题:

方案一:通过HttpContext获取当前请求的作用域服务

  1. 注册HttpContextAccessor服务
    在Program.cs中添加HttpContext访问器的注册,这是ASP.NET Core获取当前请求上下文的标准方式:

    builder.Services.AddHttpContextAccessor();
    
  2. 修改自定义渲染器的依赖注入
    将渲染器的构造函数改为注入IHttpContextAccessor,而非全局的IServiceProvider,这样就能直接拿到当前请求的上下文:

    public class HelloWorldLayoutRenderer : LayoutRenderer
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
    
        public HelloWorldLayoutRenderer(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }
    
        protected override void Append(StringBuilder builder, LogEventInfo logEvent)
        {            
            builder.Append("hello world!");
            var httpContext = _httpContextAccessor.HttpContext;
            if (httpContext != null)
            {
                // 从当前请求的服务容器中直接获取已赋值的ApplicationContext
                var applicationContext = httpContext.RequestServices.GetService<ApplicationContext>();
                builder.Append(applicationContext?.CurrentUserUuid);
            }
        }
    }
    
  3. 更新渲染器的实例化逻辑
    在注册渲染器时,从全局服务容器中获取IHttpContextAccessor实例传入:

    ConfigurationItemFactory.Default.CreateInstance = (Type type) =>
    {
        if (type == typeof(HelloWorldLayoutRenderer))
            return new HelloWorldLayoutRenderer(app.Services.GetRequiredService<IHttpContextAccessor>());
        else
            return Activator.CreateInstance(type); 
    };
    

方案二:将用户信息存入NLog诊断上下文(更轻量)

这种方式无需依赖服务容器,直接将需要的用户信息存入NLog的逻辑诊断上下文,渲染器直接读取即可:

  1. 在中间件中存入用户信息
    修改中间件代码,将CurrentUserUuid存入NLog的MappedDiagnosticsLogicalContext(MDLC),它会和当前异步请求上下文绑定:

    public async Task Invoke(HttpContext httpContext, ApplicationContext applicationContext)
    {
        string? loggedInUserUuid = httpContext.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        if (loggedInUserUuid != null)
        {
            applicationContext.CurrentUserUuid = Guid.Parse(loggedInUserUuid);
            // 将用户ID存入NLog诊断上下文
            MappedDiagnosticsLogicalContext.Set("CurrentUserUuid", applicationContext.CurrentUserUuid);
        }
        await _next(httpContext);
    }
    
  2. 修改渲染器直接读取诊断上下文的值
    渲染器无需注入任何服务,直接从MDLC中读取值:

    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {            
        builder.Append("hello world!");
        // 从NLog诊断上下文获取用户ID
        var currentUserUuid = MappedDiagnosticsLogicalContext.Get("CurrentUserUuid");
        builder.Append(currentUserUuid?.ToString());
    }
    

注意:如果存在后台任务等非请求上下文的日志场景,方案一中的HttpContext会为null,需要额外做null判断;方案二中MDLC的值仅在当前请求异步流内有效,非请求场景不会有值。

内容的提问来源于stack exchange,提问作者ValidfroM

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 11:10:42