[英]Using IoC in a custom Log4Net appender
不幸的是,當我使用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;
}
}
但是我不調用container.Resolve<WcfAppender>()
它在log4net庫中調用new WcfAppender()
。 如何告訴log4net庫使用new WcfAppender(factoryGeneratedFromUnity)
呢?
我認為samy是對的 ,這是我如何解決它的實現。
在我初始化Unity容器之前調用了ActivateOptions()
,所以為了安全起見我只是將工廠方法的檢索放在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>>();
//...
從我在代碼中看到的,appender是由ParseAppender
方法中的XmlHierarchyConfigurator
類創建的:
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>
該方法通過調用IOptionHandler
接口實現的方法完成加載appender(您已經在appender中使用它,因為您的祖先樹中有AppenderSkeleton
類)
IOptionHandler optionHandler = appender as IOptionHandler;
if (optionHandler != null)
{
optionHandler.ActivateOptions();
}
log4net未知的任何xml參數都將推送到具有相同名稱的屬性。 因此,可以完全從xml配置文件配置appender,並通過讓appender實現IOptionHandler
啟動所需的任何特定行為
您必須將Func<ClientLoggerClient>
傳遞給appender的唯一方法(重建自定義log4net)是使用您在Apateder中調用的靜態事件, ActivateOptions()
方法將由您的解析方法獲取的事件選擇; 該事件可以包含來自appender的xml配置的一些自定義,因此您可以基於此來路由解析。 讓事件給你的appender提供足夠的Func<ClientLoggerClient>
,你就可以了。
我能夠在創建后通過Unity容器運行appender實例:
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);
BuildUp()
方法將填充appender類中的injection屬性:
public class LogDatabaseSaverAppender : AppenderSkeleton
{
[Dependency]
public IContextCreator ContextCreator { get; set; }
...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.