2012-02-17 2 views
0

Я использую Castle Windsor 3.0 для инъекций зависимостей в демонстрационном приложении ASP.NET. Один из моих контроллеров принимает экземпляр ICustomerService, который, в свою очередь, принимает экземпляр ISession, все через конструктор. ISession зарегистрирован в Windsor с использованием заводского метода и стиля жизни PerWebRequest.Сделка исчезает при использовании windsor + nhibernate

_container.Register(Component.For<ISessionFactory>().Instance(DbHelper.BuildSessionFactory()).LifestyleSingleton()); 
_container.Register(Component.For<ISession>().LifestylePerWebRequest().UsingFactoryMethod(x => x.Resolve<ISessionFactory>().OpenSession())); 

В файле global.asax, у меня есть обработчик Application_EndRequest, который пытается совершить сделку:

protected void Application_EndRequest(object sender, EventArgs e) 
{ 
    if (!IsStaticResourceRequest()) 
    { 
     var app = (HttpApplication)sender; 
     var factory = _container.Resolve<ISessionFactory>(); 
     var session = ManagedWebSessionContext.Unbind(Context, factory); 

     if (session != null && 
      session.Transaction != null && 
      session.Transaction.IsActive) 
     { 
      session.Transaction.Commit(); 
      session.Transaction.Dispose(); 
      session.Dispose(); 
     }      
    } 
} 

Проблема заключается в том, что PerWebRequest образ жизни Виндзор имеет свой собственный обработчик события Application_EndRequest который распоряжается службы до моего обработчика Application_EndRequest (в global.asax), поэтому код в моем обработчике Application_EndRequest никогда не получает возможности совершить транзакцию. Есть ли обходной путь для этого?

ответ

0

Решение закончило тем, что я совершил транзакцию в случае, ранее существовавшего в жизненном цикле ASP.NET. Я выбрал ReleaseRequestState, но любой из методов, ведущих к событию EndRequest, должен быть достаточным, если обработчик завершил обработку запроса.

0

Я отошел от этого шаблона и скорее совершил совершение в действии вашего контроллера. Зачем ждать, пока вы не покинете страницу и в конце запроса перед совершением. Делает передачу UI-сообщений намного сложнее. В настоящее время я беру в ISession как пары в контроллере для обеспечения он получает инъекцию:

public void SomeController(ISession session) 
{ 
    _session = session; 
} 

затем в вашем действии:

using(var trans = new _session.BeginTransaction()){ 
    try{ 
    ..update etc 
    trans.commit(); 
    } 
    catch(Exception ex){ 
    trans.rollback(); 
    // return message, log etc 
    } 
} 

Windsor будет очистка сеанса для вас в конце запроса ,

+0

Это может работать для простых изолированных случаев, но представьте себе действие контроллера, которое вызывает несколько служб или обращается к нескольким репозиториям через их отдельную (но идентичную для каждого запроса веб-запроса) ссылку на сеанс. Вы не можете иметь более одной активной транзакции за сеанс. – Chris

+0

Привет Крис. Я использую это только для «простых изолированных случаев». Тот же сеанс используется повторно, так как Windosor вернет тот же сеанс для срока службы запроса. Мой комментарий был больше о том, как долго вы хотите открывать транзакции и где вы хотите совершить транзакции. Также становится более сложным показывать сообщения об ошибках клиентам, когда вы полагаетесь на транзакции, которые должны быть совершены в конце запроса. Я предпочитаю обрабатывать ошибки в контроллере и отображать соответствующие сообщения клиенту. – Chev

Смежные вопросы