c# - 在自定义 Log4Net appender 中使用 IoC

标签 c# inversion-of-control log4net unity-container

不幸的是,当我使用 Log4Net 搜索涉及 Unity 或 IoC 的任何内容时,我已经搜索了很长时间,我得到的唯一结果是如何制作 ILog通过 IoC 自动填充。这不是我想要做的。

我有一个自定义 Appender,它通过 WCF 将数据传输到服务器。我想做的是传入一个工厂方法,最好是 Unity 生成的方法,它为我创建 WCF 客户端类,这样我就可以在单元测试期间将真正的客户端类换成 stub 。问题是我在任何地方都找不到关于如何将参数传递给自定义 log4net appender 的任何解释。

这是我通常使用 Unity 实现它的方式。

public class WcfAppender : BufferingAppenderSkeleton
{
    public WcfAppender(Func<ClientLoggerClient> loggerClientFactory) //How do I get this Func passed in?
    {
        LoggerClientFactory = loggerClientFactory;
    }


    private readonly Func<ClientLoggerClient> LoggerClientFactory; 
    private static readonly ILog Logger = LogManager.GetLogger(typeof(WcfAppender));
    private static readonly string LoggerName = typeof(WcfAppender).FullName;

    public override void ActivateOptions()
    {
        base.ActivateOptions();
        this.Fix = FixFlags.All;
    }

    protected override bool FilterEvent(LoggingEvent loggingEvent)
    {
        if (loggingEvent.LoggerName.Equals(LoggerName))
            return false;
        else
            return base.FilterEvent(loggingEvent);
    }


    protected override void SendBuffer(LoggingEvent[] events)
    {
        try
        {
            var client = LoggerClientFactory();
            try
            {
                client.LogRecord(events.Select(CreateWrapper).ToArray());
            }
            finally
            {
                client.CloseConnection();
            }
        }
        catch (Exception ex)
        {
            Logger.Error("Error sending error log to server", ex);
        }
    }

    private ErrorMessageWrapper CreateWrapper(LoggingEvent arg)
    {
        var wrapper = new ErrorMessageWrapper();

        //(Snip)

        return wrapper;
    }
}

但是我不叫container.Resolve<WcfAppender>() new WcfAppender() 在 log4net 库中被调用。我如何告诉 log4net 库使用 new WcfAppender(factoryGeneratedFromUnity)相反?

最佳答案

我认为samy is right ,这是我如何解决它的实现。

ActivateOptions() 在我初始化我的 Unity 容器之前被调用,所以为了安全起见,我只是将工厂方法的检索放在 SendBuffer 方法中。我最终使用 LogManager.GetRepository().Properties 属性来存储工厂对象。

public class WcfAppender : BufferingAppenderSkeleton
{
    private static readonly ILog Logger = LogManager.GetLogger(typeof(WcfAppender));
    private static readonly string LoggerName = typeof(WcfAppender).FullName;

    public override void ActivateOptions()
    {
        base.ActivateOptions();
        this.Fix = FixFlags.All;
    }

    protected override bool FilterEvent(LoggingEvent loggingEvent)
    {
        if (loggingEvent.LoggerName.Equals(LoggerName))
            return false;
        else
            return base.FilterEvent(loggingEvent);
    }


    protected override void SendBuffer(LoggingEvent[] events)
    {
        try
        {
            var clientFactory = log4net.LogManager.GetRepository().Properties["ClientLoggerFactory"] as Func<ClientLoggerClient>;
            if (clientFactory != null)
            {
                var client = clientFactory();
                try
                {
                    client.LogRecord(events.Select(CreateWrapper).ToArray());
                }
                finally
                {
                    client.CloseConnection();
                }
            }
        }
        catch (Exception ex)
        {
            Logger.Error("Error sending error log to server", ex);
        }
    }

    private ErrorMessageWrapper CreateWrapper(LoggingEvent arg)
    {
        var wrapper = new ErrorMessageWrapper();

        //SNIP...

        return wrapper;
    }

}

然后我创建工厂并在我的程序启动期间存储它。

static class Program
{
    private static readonly ILog Logger = LogManager.GetLogger(typeof(Program));

    static void Main(string[] args)
    {
        log4net.Util.SystemInfo.NullText = String.Empty;

        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

        Logger.Debug("Service Starting");
        using (var container = new UnityContainer())
        {
            var debugMode = args.Contains("--debug", StringComparer.InvariantCultureIgnoreCase);

            BaseUnityConfiguration.Configure(container, debugMode);
            LogManager.GetRepository().Properties["ClientLoggerFactory"] = container.Resolve<Func<ClientLoggerClient>>();

            //...

关于c# - 在自定义 Log4Net appender 中使用 IoC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23634472/

相关文章:

log4net - 如何为每个附加程序定义不同的记录器级别

log4net - BufferingForwardingAppender - 超时刷新

c# - 从方法提前返回时,async/await 是否有额外的成本?

c# - 在 python 中写入结构化数据并在 C# 中读取的最轻松的方法

c# - 通用 IoC 实践——服务相互依赖是错误的吗?

node.js - NestJs运行时注入(inject)

mvvm - 使用 Unity 2.0 对 "Blendable"ViewModelLocator 的建议

c# - List<T> as 'out' 参数导致错误。为什么?

c# - 如何在 MVC 项目中使用 linqtotwitter 搜索推文

c# - log4net,单独的进程,单独的 RollingFileAppenders