嘿有人,这里有一个小问题,我试图包裹我的头。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