c# – 自定义NLog LayoutRenderer,带有使用依赖注入的构造函数

我正在尝试编写一个自定义的LayoutRenderer来记录从对象读取的数据,但似乎NLog在依赖注入时无法正常工作.

这是我的CustomLayoutRenderer:

[LayoutRenderer("custom-value")]
public class CustomLayoutRenderer : LayoutRenderer
{
    private readonly RequestContext _context;

    public CustomLayoutRenderer(RequestContext context)
    {
        _context = context;
    }

    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        builder.Append(_context.CustomValue);
    }
}

它正在使用此RequestContext对象:

public class RequestContext
{
    public string CustomValue { get; set; } = "Valid custom value";
}

我也在连接DI,配置NLog并在Startup.cs中注册我的LayoutRenderer:

    public void ConfigureServices(IServiceCollection services)
    {
        // ...
        services.AddScoped<RequestContext>();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        LayoutRenderer.Register<CustomLayoutRenderer>("custom-value");

        loggerFactory.AddNLog();
        app.AddNLogWeb();
        env.ConfigureNLog("nlog.config");
        // ...
    }

然后我尝试在nlog.config中使用我的${custom-value},但是我在AddNLog()调用时遇到错误:

2017-02-03 13:08:08.0284 Error Parsing configuration from [project-folder]\bin\Debug\net452\win7-x64\NLog.config failed.
Exception: NLog.NLogConfigurationException: Exception when parsing [project-folder]\bin\Debug\net452\win7-x64\NLog.config.
NLog.NLogConfigurationException: Cannot access the constructor of type: ATest.CustomLayoutRenderer. Is the required permission granted?
at NLog.Internal.FactoryHelper.CreateInstance(Type t)

笔记

我之所以这样做是因为我想记录一些只能从控制器访问的信息(比如TraceIdentifier,URL的一部分,以及一些特定于请求的自定义内容). RequestContext中的值将在获取请求时由控制器设置.

以下渲染器按预期工作,这让我觉得这是一个依赖注入问题:

[LayoutRenderer("custom-value")]
public class CustomLayoutRenderer : LayoutRenderer
{
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        builder.Append("Hello, World!");
    }
}

我确实看到了这个NLog bug,但它现在被标记为固定,这就是为什么我在这里而不是在那里发布.

为了完整起见,这是我添加到我的project.json中的内容:

"dependencies": {
    ...
    "NLog.Extensions.Logging": "1.0.0-*",
    "NLog.Web.AspNetCore": "4.3.0"
},

解决方法:

两种方法:

1)DI意识到

你可以让NLog DI知道.添加到您的startup.cs:

ConfigurationItemFactory.Default.CreateInstance = (Type type) =>
{ 
    // your custom target. Could be a better check ;)
    if(type == typeof(CustomLayoutRenderer))
      return new CustomLayoutRenderer(...); // TODO get RequestContext
    else
      return Activator.CreateInstance(type); //default
};

这是一种更通用的方法.

2)AspNetMvcLayoutRendererBase

或者,从AspNetMvcLayoutRendererBase(NLog.Web.AspNetCore)覆盖并使用HttpContextAccessor?.HttpContext?.TryGetRequest()并且不添加构造函数.

这仅在需要HttpContext时有效.

[LayoutRenderer("custom-value")]
public class MyCustomRenderer : AspNetLayoutRendererBase
{
    protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
    {
        var httpRequest = HttpContextAccessor?.HttpContext?.TryGetRequest();

        if (httpRequest == null)
            return;


        builder.Append(httpRequest.Something); //TODO

    }
}
上一篇:.Net Core 中使用NLog作为日志中间件


下一篇:c# – Windsor Logging Facility:控制日志名称