NHibernate + WCF + Служба Windows и класс WcfOperationSessionContext - PullRequest
7 голосов
/ 22 марта 2011
  • У меня есть приложение-служба Windows в котором я создаю службы WCF в нем.
  • Одной из услуг является передача данных услуги: добавить, удалить, читать, обновлять данные через WCF.
  • WCF использует NHibernate для манипулирования данными

Итак, мои предположения:

  • Любой совет (лучшая практика) по управлению сессиями для использования Hibernate с WCF?

  • Кто-нибудь знает что-нибудь о

WcfOperationSessionContext (hibernate 3.0) класс?

how to use it with WCF?

Хорошо, чтобы сделать это конкретным:

Предположим, у меня есть служба WCF, которая называется DataServices

class WCFDataService .....
{

   void SaveMyEntity(MyEntity entity)
    {



         .....................?? // How to do? Best Way

         // Should i take one session  and use it all times
         // Should i take session and dipsose when operation finished then get 
         //new session for new operations?
         // If many clients call my WCF service function at the same time?
         // what may go wrong?
         // etc....


     }


 }

И мне нужен NHibernateServiceProvider класс

class NHibernateServiceProvider ....
{

    // How to get Session ?? Best way

     ISession GetCurrentSession(){.... }
     DisposeSession(){ ....}
}

С наилучшими пожеланиями

PS: Я читал похожие записи здесь и на других веб-страницах. Но не вижу «конкретных» ответов.

Ответы [ 4 ]

9 голосов
/ 22 марта 2011

WcfOperationSessionContext, аналогично ThreadStaticSessionContext и WebRequestSessionContext, является реализацией для контекста сеанса. Контекст сеанса используется для привязки (связывания) экземпляра ISession к определенному контексту.

Сеанс в текущем контексте можно получить, вызвав ISessionFactory.GetCurrentSession ().

Более подробную информацию о контексте сеанса можно найти здесь .

WcfOperationSessionContext представляет контекст, который охватывает всю продолжительность операции WCF. Вам по-прежнему необходимо обрабатывать привязку сеанса в начале операции и отмену привязки / фиксации / удаления сеанса в конце операции.

Чтобы получить доступ к действиям начала / конца в конвейере wcf, вам нужно реализовать IDispatchMessageInspector. Вы можете увидеть образец здесь .

Также в отношении интеграции WCF: если вы используете контекст сеанса ThreadStatic, он, похоже, будет работать в процессе разработки, но вы попадете в стену в производственном процессе, когда различные компоненты (например, авторизация, аутентификация) из конвейера wcf будут выполняться в разных потоках.

Что касается передового опыта, вы его почти прибили: используйте WcfOperationSessionContext для хранения текущего сеанса и IDispatchMessageInspector для начала / завершения вашей единицы работы.

РЕДАКТИРОВАТЬ - для адресации добавленные вами данные : Если вы настроили WcfOperationSessionContext и выполнили привязку / отмену привязки, как я объяснил выше, все, что вам нужно сделать, это внедрить ISessionFactory в вашу службу и просто использовать factory.GetCurrentSession (). Я опубликую примерный документ, если позволит время.

Вот пример проекта

5 голосов
/ 23 марта 2011

Модель, которую мы используем для управления сессиями NHibernate с WCF, выглядит следующим образом:

1) У нас есть собственный класс ServiceHost, который наследуется от System.ServiceModel.ServiceHost, который также реализует ICallContextInitializer. Мы добавляем экземпляр узла службы к каждой из операций в нашем сервисе следующим образом:

protected override void InitializeRuntime()
{
    base.InitializeRuntime();
    foreach (ChannelDispatcher cd in this.ChannelDispatchers)
    {
        foreach (EndpointDispatcher ed in cd.Endpoints)
        {
            foreach (DispatchOperation op in ed.DispatchRuntime.Operations)
            {
                op.CallContextInitializers.Add(this);
             }
        }
    }
}

public void AfterInvoke(object correlationState)
{
    // We don't do anything after the invoke
}

public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
{
    OperationContext.Current.Extensions.Add(new SessionOperationContext());
    return null;
}

BeforeInvoke просто гарантирует, что OperationContext для каждого вызова WCF имеет свой собственный сеанс. Мы обнаружили проблемы с IDispatchMessageInspector, когда сеанс недоступен во время сериализации ответов - проблема, если вы используете отложенную загрузку.

2) Затем будет вызываться наш SessionOperationContext, чтобы присоединиться, и мы используем событие OperationCompleted, чтобы удалить себя. Таким образом, мы можем быть уверены, что сессия будет доступна для сериализации ответов.

public class SessionOperationContext : IExtension<OperationContext>
{

    public ISession Session { get; private set; }

    public static SessionOperationContext Current
    {
        get
        {
            OperationContext oc = OperationContext.Current;
            if (oc == null) throw new InvalidOperationException("Must be in an operation context.");
            return oc.Extensions.Find<SessionOperationContext>();
        }
    }

    public void Attach(OperationContext owner)
    {
        // Create the session and do anything else you required
        this.Session = ... // Whatever instantiation method you use

        // Hook into the OperationCompleted event which will be raised
        // after the operation has completed and the response serialised.
        owner.OperationCompleted += new EventHandler(OperationCompleted);
    }

    void OperationCompleted(object sender, EventArgs e)
    {
        // Tell WCF this extension is done
        ((OperationContext)sender).Extensions.Remove(this);
    }

    public void Detach(OperationContext owner)
    {
        // Close our session, do any cleanup, even auto commit 
        // transactions if required.
        this.Session.Dispose();
        this.Session = null;
    }
}

Мы успешно использовали вышеуказанный шаблон в приложениях с высокой нагрузкой, и, похоже, он хорошо работает.

В целом, это похоже на то, что делает новый WcfOperationSessionContext (этого не было, когда мы разобрались с шаблоном выше ;-)), но также преодолевает проблемы, связанные с отложенной загрузкой.

Относительно дополнительных вопросов: Если вы используете модель, изложенную выше, вы просто сделаете следующее:

void SaveMyEntity(MyEntity entity)
{
    SessionOperationContext.Current.Session.Save(entity);
}

Вам гарантируется, что сеанс всегда присутствует и что он будет удален после завершения операции WCF. При необходимости вы можете использовать транзакции обычным способом.

3 голосов
/ 30 марта 2011

Вот запись , подробно описывающая все шаги для регистрации и использования WcfOperationSessionContext. В него также включены инструкции по его использованию с проектом agatha-rrsl.

1 голос
/ 16 марта 2013

Хорошо, после нескольких дней чтения интернет-сообщений и т. Д. Все подходы, показанные в интернете, кажутся неправильными. Когда мы используем шаблон UnitOfWork с NH 3 ^ с транзакцией nhibernate, все апроксы вызывают исключения. Чтобы проверить это и доказать, что нам нужно создать тестовую среду с очередью транзакций MSMQ, специальный интерфейс с контрактом операции OneWay с требуемой транзакцией установлен на нем. Этот подход должен работать так: 1. Ставим транзакционное сообщение в очередь. 2. Сервис получает транзакционное сообщение из очереди. 3. Все работает, очередь пуста.

В некоторых случаях, когда Интернет-подходы не так очевидны, это не работает должным образом. Итак, вот примеры, которые мы проверили, которые неправильны и почему:

  1. Подход Фабио Мауло: Использовать ICallContextInitializer - открыть сеанс / транзакцию NH на BeforeCall, после этого WCF выполняет метод обслуживания, на AfterCall в инициализаторе контекста мы вызываем session.Flush + Transactions.commit. Автоматически сессия будет сохранена, когда область транзакции совершит операцию. В ситуации, когда при вызове транзакции. Полное исключение будет сгенерировано, WCF-служба отключится! Вопрос может быть в порядке, поэтому возьмите транзакцию. Завершите в разделе «попробуй / поймай» - отлично! - Без ошибок! Тогда область действия транзакции будет зафиксирована, и сообщение будет извлечено из очереди, но данные не будут сохранены!
  2. Другой подход заключается в использовании IDispatchMessageInspector - вчера я подумал, что это лучший подход. Здесь нам нужно открыть сеанс / транзакцию в методе AfterReceiveRequest, после того, как WCF вызовет операцию службы для инспектора диспетчера сообщений BeforeSendReply. В этом методе у нас есть информация о [reply], которая в операции OneWay имеет значение null, но заполняется информацией об ошибках, если она произошла при вызове метода службы. Здорово я подумала - вот это! но нет! Проблема в том, что на данный момент в конвейере обработки WCF у нас нет транзакции! Так что если вы выбросите транзакцию error.Complete throw или session.Flush, у нас не будет данных, сохраненных в базе данных, и сообщение не вернется в очередь, что не так.

Какое решение?

IOperationInvoker и только это!

Вам нужно реализовать этот интерфейс как шаблон декоратора по умолчанию в invoker. В методе Invoke перед вызовом мы открываем сессию / транзакцию открытой, затем мы вызываем invoke по умолчанию invoker, и после этого вызоваaction.complete в разделе finally мы вызываем session.flush. Какие типы проблем это решает: 1. У нас есть область транзакции на этом уровне, поэтому, когда сообщение об исключении завершенных бросков вернется в очередь, WCF не завершит работу. 2. Когда вызов вызовет исключение, не будет вызываться транзакция. То, что не изменит состояние базы данных

Надеюсь, это очистит всякую недостоверную информацию.

В свободное время я постараюсь написать пример.

...