Привет, ребята, у меня есть небольшая проблема, которую я пытаюсь обернуть.
В настоящее время я начинаю с nHibernate, так что мне это нужно из-за рабочих требований, и я немного застреваю с сессиями nHibernate и несколькими потоками. Итак, задача, которую я хочу выполнить, состоит в том, чтобы Log4Net регистрировал все в базе данных, включая отладку / ошибки nHibernate и т. Д.
Итак, я создал очень простой класс Log4Net: AppenderSkeleton, который срабатывает идеально, когда мне это нужно. Основная проблема, с которой я столкнулся, заключалась в том, что, когда я использовал GetCurrentSession, очевидно, что, поскольку Log4Net работает в отдельном потоке (ах), он завершился ошибкой во время сеанса исходного потока. Поэтому я решил, что мне нужно создать новую сессию nHiberante для класса Log4Net AppenderSkeleton. Код ниже:
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, но я не уверен, что да. Имея в виду, что я уже связываю Session с начальным потоком, используя нижеприведенное ниже в Global.asax (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;
}
}
}
Я понимаю, что могу использовать приложение ADO в log4net, но я хочу использовать nHibernate напрямую, чтобы добавить данные в базу данных. Причина в том, что я не хочу возиться со строками соединений и т. Д., Когда nHibernate уже работает.
Как всегда, любая помощь всегда ценится.
- Изменить: -
Итак, исходя из того, что мне сказали вначале, я изменил свой код регистратора Log4Net. Ниже представлены две версии. Мой вопрос, что лучше или есть лучший способ?
Первый, согласно nHibernate Prof, создает только два сеанса. Первый сеанс предназначен для основного потока программы, как и предполагалось, а второй - для кода моего регистратора 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();
}
}
}