Я поднял этот вопрос прежде, но все еще изо всех сил пытаюсь найти пример, что я могу получить голову вокруг (только скажите мне смотреть на проект Архитектуры S#arp по крайней мере без некоторых направлений).
До сих пор я достиг близкого незнания постоянства в своем веб-проекте. Мои классы репозитория (в моем проекте данных) берут ISession в конструкторе:
public class ProductRepository : IProductRepository
{
private ISession _session;
public ProductRepository(ISession session) {
_session = session;
}
В моем global.asax я выставляю текущую сессию, и создаю и располагаю сессию на beginrequest и endrequest (это - то, где у меня есть зависимость от NHibernate):
public static ISessionFactory SessionFactory = CreateSessionFactory();
private static ISessionFactory CreateSessionFactory() {
return new Configuration()
.Configure()
.BuildSessionFactory();
}
protected MvcApplication() {
BeginRequest += delegate {
CurrentSessionContext.Bind(SessionFactory.OpenSession());
};
EndRequest += delegate {
CurrentSessionContext.Unbind(SessionFactory).Dispose();
};
}
И наконец мой реестр StructureMap:
public AppRegistry() {
For<ISession>().TheDefault
.Is.ConstructedBy(x => MvcApplication.SessionFactory.GetCurrentSession());
For<IProductRepository>().Use<ProductRepository>();
}
Казалось бы, что мне нужны мои собственные универсальные реализации ISession и ISessionFactory, который я могу использовать в своем веб-проекте и ввести в свои репозитории?
Так просто для уточнения - я использую NHibernate в своем слое репозитория и хочу использовать session-per-(http) запрос. Поэтому я ввожу ISession в своих конструкторов репозитория (использующий structuremap). В настоящее время, чтобы создать и расположить сессии в каждом запросе я должен был сослаться на NHibernate из своего веб-проекта. Это - зависимость, которую я хотел бы удалить.
Спасибо, Ben
Почему бы вам не создать IHttpModule и не выполнить его создание и размещение там (вероятно, в Begin_Request и End_Request событий), а поместить IHttpModule внутрь проекта, который имеет вашу зависимость NHibernate. Например.
namespace MyWebApp.Repository.NHibernateImpl
{
public class NHibernateModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(Context_BeginRequest);
context.EndRequest += new EventHandler(Context_EndRequest);
}
private void Context_BeginRequest(object sender, EventArgs e)
{
// Create your ISession
}
private void Context_EndRequest(object sender, EventArgs e)
{
// Close/Dispose your ISession
}
public void Dispose()
{
// Perhaps dispose of your ISessionFactory here
}
}
}
Может быть, есть лучший способ, мне интересно узнать и об этом, так что есть ли альтернативные предложения?
Спасибо всем за помощь. Немного больше исследований привело меня к проекту NHibernate Burrow.
Из проекта FAQ ( http://nhforge.org/wikis/burrow/faq.aspx ):
Burrow - это легкое промежуточное программное обеспечение, разработанное для поддержки приложений .Net, использующих NHibernate (возможно, также называется NH в этой статье) как ORM framework. Использование Asp.net с NHibernate может быть проблемой из-за того, что NHibernate - это среда с отслеживанием состояния, а Asp.net - среда без отслеживания состояния.Burrow может помочь решить этот конфликт, предоставляя расширенное и интеллектуальное управление сеансами / транзакциями и другие средства.
Мне пришлось преодолеть несколько препятствий, чтобы заставить его работать в моем проекте. Поскольку в текущем выпуске используется старая версия NHibernate, мне пришлось загрузить последний исходный код из магистрали, открыть в VS, добавить ссылки на последнюю версию NHibernate и перекомпилировать (к счастью, без ошибок).
Я тестировал NHibernate Burrow несколькими способами.
1) Продолжить внедрение ISession в мои репозитории
Для этого мне пришлось добавить ссылки на NHibernate, NHibernate.Burrow и NHibernate.Burrow.WebUtil в мой проект MVC.
В web.config мне пришлось настроить Burrow (см. http://nhforge.org/wikis/burrow/get-started.aspx ), а затем в моем реестре StructureMap добавить следующее:
For<ISession>()
.TheDefault.Is
.ConstructedBy(x => new NHibernate.Burrow.BurrowFramework().GetSession());
Мне нравится этот подход, поскольку он означает, что мои репозитории (или контроллеры) не связаны с Burrow. Мне не очень нравится тот факт, что я должен ссылаться на эти три сборки в моем веб-проекте, но, по крайней мере, я теряю код для управления сеансом - всем этим занимается Burrow.
2) Второй подход заключался бы в установке ISession в конструкторах моих репозиториев следующим образом:
public ProductRepository() :
this(new BurrowFramework().GetSession()) { }
public ProductRepository(ISession session) {
_session = session;
}
Я все еще могу переопределить ISession, делая мои репозитории тестируемыми. Тогда у меня есть прямая зависимость от Burrow, но, может быть, это не так уж и плохо?
С другой стороны, единственная сборка, на которую мне нужно ссылаться из моего веб-проекта, - это NHibernate.Burrow.WebUtils.
Интересно посмотреть, кто из двух человек пойдет на это и почему.
На мой взгляд, вы должны принять ISession и работать с ним напрямую. Проблема многих реализаций session-per-request в том, что они откладывают фиксацию изменений в базе данных до окончания HTTP-запроса. Если транзакция завершится неудачно, все, что вы можете сделать в этот момент, это направить пользователя на страницу общей ошибки. Гораздо лучше управлять транзакцией на странице, чтобы можно было более эффективно отлавливать и обрабатывать ошибки. Если вы пойдете этим путем, то для управления транзакцией вам потребуется доступ к ISession или обертке.
Кроме того, в какой-то момент вашему приложению, вероятно, понадобится использовать свойства или методы, открытые ISession, особенно Merge и Load.