嘿有人,這裏有一個小問題,我試圖包裹我的頭。nHibernate與Log4Net日誌記錄,線程會話問題
我現在開始與nHibernate,這樣我必須由於工作要求,並且有點卡住nHibernate的會話和多個線程。那麼我想在這裏完成的任務是讓Log4Net將所有東西都記錄到數據庫中,包括nHibernate的調試/錯誤等。
所以我做的是創建一個非常簡單的Log4Net:AppenderSkeleton類,當我需要它時會完全啓動。我碰到的一個初始問題是,當我使用GetCurrentSession時,很明顯,因爲Log4Net運行在一個單獨的線程上,所以它在初始線程的會話中出錯。所以我想我必須爲Log4Net AppenderSkeleton類創建一個新的nHiberante會話。代碼如下:
public class Custom : AppenderSkeleton
{
protected override void Append(LoggingEvent loggingEvent)
{
if (loggingEvent != null)
{
using (ISession session = NHibernateHelper.OpenSession())
{
using (ITransaction tran = session.BeginTransaction())
{
Log data = new Log
{
Date = loggingEvent.TimeStamp,
Level = loggingEvent.Level.ToString(),
Logger = loggingEvent.LoggerName,
Thread = loggingEvent.ThreadName,
Message = loggingEvent.MessageObject.ToString()
};
if (loggingEvent.ExceptionObject != null)
{
data.Exception = loggingEvent.ExceptionObject.ToString();
}
session.Save(data);
tran.Commit();
}
}
}
}
足夠簡單的想法真的,而這是在它的基本形式,現在,我將有更多的錯誤檢查信息等,但現在的問題是,雖然這工作完全是創建多個會話。也就是說,它創建一個新的會話記錄每個錯誤,因爲我不能使用GetCurrentSession,因爲這會得到調用會話(主程序流)。我確信有一種方法可以爲Log4Net的線程創建全局會話,但我不確定。請記住,我已經使用了下面的Global.asax綁定一個Session到INTIAL線程(的Application_BeginRequest):
ISession session = NHibernateHelper.OpenSession();
CurrentSessionContext.Bind(session);
而對於那些會問,我的助手的內容是以下(這是在DLL):
public static class NHibernateHelper
{
private static Configuration _nHibernateConfig;
private static ISessionFactory _nHibernateSessionFactory;
private static ISessionFactory BuildNHibernateSessionFactory
{
get
{
if (_nHibernateSessionFactory == null)
{
if (_nHibernateConfig == null)
{
BuildSessionFactory();
}
_nHibernateSessionFactory = _nHibernateConfig.BuildSessionFactory();
}
return _nHibernateSessionFactory;
}
}
private static Configuration BuildNHibernateConfig
{
get
{
if (_nHibernateConfig == null)
{
_nHibernateConfig = new ConfigurationBuilder().Build();
}
return _nHibernateConfig;
}
}
public static Configuration nHibernateConfig
{
get
{
return _nHibernateConfig;
}
}
public static ISessionFactory nHibernateSessionFactory
{
get
{
return _nHibernateSessionFactory;
}
}
public static Configuration BuildConfiguration()
{
return BuildNHibernateConfig;
}
public static ISessionFactory BuildSessionFactory()
{
return BuildNHibernateSessionFactory;
}
public static ISession OpenSession()
{
return _nHibernateSessionFactory.OpenSession();
}
public static ISession GetCurrentSession()
{
try
{
return _nHibernateSessionFactory.GetCurrentSession();
}
catch (HibernateException ex)
{
if(ex.Message == "No session bound to the current context")
{
// See if we can bind a session before complete failure
return _nHibernateSessionFactory.OpenSession();
}
else
{
throw;
}
}
catch (Exception ex)
{
throw;
}
}
}
我知道我可以在log4net的使用ADO附加目的地,但我希望使用NHibernate的直接將數據添加到數據庫中。原因是當nHibernate已經在工作時,我不希望混淆連接字符串等。
一如既往,任何幫助總是讚賞。
- 編輯: -
因此,基於我一直initialy說,我修改了我的自定義log4net的記錄代碼。下面有兩個版本。我的問題,最好還是有更好的辦法?
首先,根據NHibernate的教授,僅創建兩會 - 該INTIAL會議是主程序流程爲目的,第二個我log4net的記錄器的代碼。然而,這在第二次會議上有數百個入口,並且抱怨太多入口和對數據庫的許多呼叫。
第二,nHibernate prof會顯示許多會話,與主程序流的記錄器+1調用一樣多的會話。然而在nHprof的任何地方都沒有投訴。雖然我有這樣的感覺,那麼多次會議會讓人皺眉頭,或者任務太多。
反正代碼:
碼1 -
protected override void Append(LoggingEvent loggingEvent)
{
if (!System.Web.HttpContext.Current.Items.Contains("Log4Net nHibernate Session"))
{
System.Web.HttpContext.Current.Items.Add("Log4Net nHibernate Session", NHibernateHelper.OpenStatelessSession());
}
IStatelessSession statelessSession = System.Web.HttpContext.Current.Items["Log4Net nHibernate Session"] as IStatelessSession;
if (statelessSession != null && loggingEvent != null)
{
using (ITransaction tran = statelessSession.BeginTransaction())
{
Log data = new Log
{
Id = Guid.NewGuid(),
Date = loggingEvent.TimeStamp,
Level = loggingEvent.Level.ToString(),
Logger = loggingEvent.LoggerName,
Thread = loggingEvent.ThreadName,
Message = loggingEvent.MessageObject.ToString()
};
if (loggingEvent.ExceptionObject != null)
{
data.Exception = loggingEvent.ExceptionObject.ToString();
}
statelessSession.Insert(data);
tran.Commit();
}
}
}
代碼2 -
protected override void Append(LoggingEvent loggingEvent)
{
if (loggingEvent != null)
{
using (IStatelessSession statelessSession = NHibernateHelper.OpenStatelessSession())
using (ITransaction tran = statelessSession.BeginTransaction())
{
Log data = new Log
{
Id = Guid.NewGuid(),
Date = loggingEvent.TimeStamp,
Level = loggingEvent.Level.ToString(),
Logger = loggingEvent.LoggerName,
Thread = loggingEvent.ThreadName,
Message = loggingEvent.MessageObject.ToString()
};
if (loggingEvent.ExceptionObject != null)
{
data.Exception = loggingEvent.ExceptionObject.ToString();
}
statelessSession.Insert(data);
tran.Commit();
}
}
}
如果您使用NHibernate來記錄NHibernate調試消息不會進入無限循環並融化您的計算機? – dotjoe 2011-04-22 17:27:41
我想你會檢查重複或重播。在任何情況下,到目前爲止,我的應用程序的啓動,這僅僅是德基礎,記錄從NHibernate的大約300調試消息並沒有循環:) – Anthony 2011-04-22 18:08:34
StatelessSession是要走的路。你不會有任何問題。 – 2011-04-23 01:19:39