C# 在自定义Log4Net appender中使用IoC

C# 在自定义Log4Net appender中使用IoC,c#,inversion-of-control,log4net,unity-container,C#,Inversion Of Control,Log4net,Unity Container,不幸的是,当我用Log4Net搜索任何涉及Unity或IoC的内容时,我得到的唯一结果是如何通过IoC自动填充ILog。这不是我想做的事 我有一个自定义的Appender,它通过WCF将数据传输到服务器。我想做的是传入一个工厂方法,最好是由Unity生成的,它为我创建WCF客户机类,这样我就可以在单元测试期间用存根替换真正的客户机类。问题是我在任何地方都找不到关于如何将参数传递到自定义log4net appender的任何解释 下面是我通常如何使用Unity实现这一点 public class

不幸的是,当我用Log4Net搜索任何涉及Unity或IoC的内容时,我得到的唯一结果是如何通过IoC自动填充
ILog
。这不是我想做的事

我有一个自定义的Appender,它通过WCF将数据传输到服务器。我想做的是传入一个工厂方法,最好是由Unity生成的,它为我创建WCF客户机类,这样我就可以在单元测试期间用存根替换真正的客户机类。问题是我在任何地方都找不到关于如何将参数传递到自定义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;
    }
}
公共类WcfAppender:BufferingAppenderSkeleton
{
public WcfAppender(Func loggerClientFactory)//如何传入此Func?
{
LoggerClientFactory=LoggerClientFactory;
}
私有只读函数LoggerClientFactory;
私有静态只读ILog Logger=LogManager.GetLogger(typeof(WcfAppender));
私有静态只读字符串LoggerName=typeof(WcfAppender).FullName;
公共覆盖无效激活选项()
{
base.ActivateOptions();
this.Fix=FixFlags.All;
}
受保护的覆盖布尔过滤器事件(LoggingEvent LoggingEvent)
{
if(loggingEvent.LoggerName.Equals(LoggerName))
返回false;
其他的
返回base.FilterEvent(记录事件);
}
受保护的重写void SendBuffer(LoggingEvent[]事件)
{
尝试
{
var client=LoggerClientFactory();
尝试
{
LogRecord(events.Select(CreateWrapper.ToArray());
}
最后
{
client.CloseConnection();
}
}
捕获(例外情况除外)
{
Logger.Error(“将错误日志发送到服务器时出错”,例如);
}
}
私有ErrorMessageWrapper CreateWrapper(LoggingEvent参数)
{
var wrapper=新的ErrorMessageWrapper();
//(剪报)
返回包装器;
}
}

但是我不调用
container.Resolve()
调用的是log4net库中的
newwcfappender()
。如何告诉log4net库使用新的WcfAppender(factoryGeneratedFromUnity)来代替?

从代码中看到,appender是由
XmlHierarchyConfigurator
类在
ParseAppender
方法中创建的:

protected IAppender ParseAppender(XmlElement appenderElement)
{
    string attribute = appenderElement.GetAttribute("name");
    string attribute2 = appenderElement.GetAttribute("type");
    // <snip>
    try
    {
        IAppender appender = (IAppender)Activator.CreateInstance(SystemInfo.GetTypeFromString(attribute2, true, true));
        appender.Name = attribute;
        // <snip>
log4net不知道的任何xml参数都会被推送到具有相同名称的属性中。因此,可以完全从xml配置文件配置appender,并通过让appender实现
IOptionHandler

您必须将
Func
传递给appender的唯一方法(重建自定义log4net)是使用appender将在
ActivateOptions()
方法中调用的静态事件,该事件将由您选择的解析方法拾取;该事件可以包含来自appender的xml配置的一些定制,因此您可以基于此路由解析。让事件将适当的
Func
返回给您的appender,您就可以开始了。

我想,下面是我如何解决它的实现

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;
    }

}
公共类WcfAppender:BufferingAppenderSkeleton
{
私有静态只读ILog Logger=LogManager.GetLogger(typeof(WcfAppender));
私有静态只读字符串LoggerName=typeof(WcfAppender).FullName;
公共覆盖无效激活选项()
{
base.ActivateOptions();
this.Fix=FixFlags.All;
}
受保护的覆盖布尔过滤器事件(LoggingEvent LoggingEvent)
{
if(loggingEvent.LoggerName.Equals(LoggerName))
返回false;
其他的
返回base.FilterEvent(记录事件);
}
受保护的重写void SendBuffer(LoggingEvent[]事件)
{
尝试
{
var clientFactory=log4net.LogManager.GetRepository().Properties[“ClientLoggerFactory”]作为Func;
if(clientFactory!=null)
{
var client=clientFactory();
尝试
{
LogRecord(events.Select(CreateWrapper.ToArray());
}
最后
{
client.CloseConnection();
}
}
}
捕获(例外情况除外)
{
Logger.Error(“将错误日志发送到服务器时出错”,例如);
}
}
私有ErrorMessageWrapper CreateWrapper(LoggingEvent参数)
{
var wrapper=新的ErrorMessageWrapper();
//剪断。。。
返回包装器;
}
}
然后,我创建工厂,并在程序启动期间存储它

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>>();

            //...
静态类程序
{
私有静态只读ILog Logger=LogManager.GetLogger(typeof(Program));
静态void Main(字符串[]参数)
{
log4net.Util.SystemInfo.NullText=String.Empty;
AppDomain.CurrentDomain.UnhandledException+=CurrentDomain\u UnhandledException;
调试(“服务启动”);
使用(var container=new UnityContainer())
{
var debugMode=args.Contains(“--debug”,StringComparer.InvariantCultureInogoreCase);
配置(容器,调试模式);
LogManager.GetRepository().Properties[“ClientLoggerFactory”]=container.Resolve();
//...

我能够通过Unity conta运行appender实例
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>>();

            //...
ILog logger = LogManager.GetLogger("My Logger");
IAppender[] appenders = logger.Logger.Repository.GetAppenders();
foreach (IAppender appender in appenders)
{
    container.BuildUp(appender.GetType(), appender);
}

container.RegisterInstance(logger);
public class LogDatabaseSaverAppender : AppenderSkeleton
{
    [Dependency]
    public IContextCreator ContextCreator { get; set; }

    ...
}