Как лучше всего уведомить пользователей об исключениях NHibernate, когда UnitOfWork - это полный запрос? - PullRequest
1 голос
/ 14 апреля 2009

В настоящее время я использую шаблон Open Session in View в приложении ASP.NET WebForms (немного адаптированный из Billy McCafferty's http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx).. Чтобы просто изложить, что здесь происходит:

  1. Открыть транзакцию NHibernate в начале запроса
  2. Фиксация в конце запроса (откат при любых ошибках)

Я обычно обрабатываю любые исключительные ошибки базы данных, фиксируя их в Application_Error (где я регистрирую, перенаправляю на страницу общих ошибок и т. Д.) Следующим образом:

        ...
          if (Context != null && Context.IsCustomErrorEnabled)
        {
            Server.Transfer(ErrorPageLocation, false);
        }
        else
        {
            log.Error("Unhandled Exception trapped in Global.asax", exception);
        }

но с NHibernate, к тому времени, когда я получаю какие-либо ошибки NHibernate / базы данных, уже слишком поздно в запросе делать мой обычный Server.Transfer (очевидно, что передача не случится так поздно в запросе) перенаправление ошибок (хотя ведение журнала все еще имеет место). В качестве очень быстрого исправления я сделал следующее в своем пользовательском HttpModule HttpApplication Context EndRequest:

        try
        {
            // Commits any open transaction and throws after rolling back any HibernateException and closing session.
            NHibernateSessionManager.Instance.CommitTransaction();
        }
        catch (HibernateException)
        {
            HttpContext.Current.Response.Redirect(ERROR_PAGE_LOCATION);
        }
        finally
        {

            NHibernateSessionManager.Instance.CloseSession();
        }

... но это пахнет не только потому, что я сейчас ссылаюсь на NHibernate в моей сети, но в основном потому, что я уверен, что должен быть лучший способ. Что было бы лучшим способом справиться с перенаправлением пользователя на общую страницу ошибок в случае ошибки базы данных / NHibernate, где, как и любые исключения, выброшенные в этот момент, выкидываются слишком поздно в процессе, чтобы обрабатываться дальше в запросе с Server.Transfer в Global.asax.cs Application_Error? Если сделать еще один шаг вперед, то с веб-сервисами это становится еще сложнее, поскольку вышеупомянутый хак, очевидно, не имеет никакого эффекта (и никакие исключения не генерируются для обработки на принимающей стороне - в моем случае, чаще всего при вызовах ajax на стороне клиента).

Пожалуйста, скажите мне, что я упускаю что-то очевидное (обычно очевидное поражает меня сразу после того, как я нажимаю "Отправить" на вопросы, подобные этим) *

Ответы [ 3 ]

2 голосов
/ 14 апреля 2009

Насколько я понимаю, шаблон открытого сеанса в представлении не обязательно означает, что единица работы открыта для всего запроса. Я справляюсь с этим (в ASP.NET MVC, а не с веб-формами, но принцип тот же), явно определяя единицу работы в моих методах контроллера. Перед возвратом метода контроллера любая транзакция базы данных была зафиксирована, поэтому в этот момент я могу правильно обработать любые ошибки обновления данных. Сеанс остается открытым, даже после того, как транзакция была зафиксирована. Для моих целей открытый сеанс в представлении полезен главным образом для обеспечения отложенной загрузки связанных объектов на этапе просмотра. Было две основные причины, по которым я решил сделать это следующим образом:

  1. Я не хотел, чтобы какие-либо транзакции базы данных оставались открытыми во время отображения представления в ответе - это необязательно, а в случае транзакций базы данных чем короче, тем лучше.
  2. При использовании шаблона 'использование' наличие явной единицы работы не требует особых усилий

Любые ошибки NHibernate, возникающие на этапе просмотра, для меня менее важны - транзакции и любые обновления уже прошли, так что я могу просто обработать их с помощью универсального обработчика ошибок перенаправления.

0 голосов
/ 14 апреля 2009

Возможно, вы могли бы объявить bool в global.asax, чтобы указать, что в предыдущем запросе произошла ошибка. Вы установили бы его в true в Application_Error, затем проверили его значение в Application_BeginRequest и перенаправили, если это правда?

0 голосов
/ 14 апреля 2009

Одна вещь, которую мы сделали, когда страница ошибки очень проста, - это просто вмешательство в Page.OnError (через базовую страницу) и выдачу html через Response. Несколько отстой, но дает вам желаемый результат в централизованном месте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...