Использование Windsor NHibernateFacility в службе Wcf с настраиваемым поведением службы для создания транзакций вместо атрибута Transaction

Я пытаюсь впервые использовать Windsor NHibernate Facility в сервисе Wcf и заменить текущую ручную регистрацию NHibernate, чтобы обеспечить единый подход ко всем сервисам.

Текущий рабочий подход

Ранее я регистрировал компоненты NHibernate вручную.

container.Register(
    Component.For<ISessionFactory>().UsingFactoryMethod(() => CreateMappings("SomeConnectionString").BuildSessionFactory()));
container.Register(
    Component.For<ISession>().LifeStyle.PerWcfOperation().UsingFactoryMethod(OpenSession));

Затем я использовал настраиваемое поведение службы для создания и завершения области транзакции для каждой операции.

public class TransactionBehavior : IServiceBehavior
{
    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (var cdb in serviceHostBase.ChannelDispatchers)
        {
            var channelDispatcher = cdb as ChannelDispatcher;

            if (null == channelDispatcher) continue;

            foreach (var endpointDispatcher in channelDispatcher.Endpoints)
            {
                foreach (var dispatchOperation in endpointDispatcher.DispatchRuntime.Operations)
                {
                    dispatchOperation.CallContextInitializers.Add(new TransactionContext());
                }
            }
        }
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { }

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }
}

public class TransactionContext : ICallContextInitializer
{
    private TransactionScope transaction;

    public Object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
    {
        transaction = new TransactionScope();
        return null;
    }

    public void AfterInvoke(Object correlationState)
    {
        if(transaction != null)
        {
        transaction.Complete();
        transaction.Dispose();
        }
    }
}

Интеграция NHibernate Facility

Я загрузил артефакты 0.3.1.2001 и, используя ресурсы, указанные ниже, попытался подключить устройство и удалить любой ручной провод до NHibernate. Однако я не хочу украшать услуги и методы Transactional а также Transaction атрибутов. Следующее - мой текущий провод.

container.Register(Component.For<INHibernateInstaller>().ImplementedBy<MyNHibernateInstaller>();
container.AddFacility<AutoTxFacility>();
container.AddFacility<NHibernateFacility>();

public class MyNHibernateInstaller : INHibernateInstaller
{
    public Maybe<IInterceptor> Interceptor { get { return Maybe.None<IInterceptor>(); } }

    public bool IsDefault { get { return true; } }

    public string SessionFactoryKey { get { return "sf.default"; } }

    public FluentConfiguration BuildFluent()
    {
        return Fluently
            .Configure()
            .Database(MsSqlConfiguration
                .MsSql2005.ConnectionString("SomeConnectionString") )
                .Mappings( m => m.FluentMappings
                    .AddFromAssemblyOf<TypeFromEntityAssembly>() );
    }

    public void Registered(ISessionFactory factory)
    {
    }
}

Всякий раз, когда я вызываю одну из конечных точек службы, происходит сбой службы со следующим исключением:

Нет транзакции в контексте при попытке создать экземпляр модели "NHibernate.ISession" для типа разрешения "Juice.iCheque.eMoneySystem.Settlement.ISettlementService". Если вы убедились, что ваш стек вызовов содержит метод с атрибутом [Transaction], то также убедитесь, что вы зарегистрировали средство AutoTx.

Вопрос в том, как использовать NHibernateFacility с моей текущей реализацией и не использовать Transaction приписывать.

Ресурсы

http://richarddingwall.name/2010/08/17/one-nhibernate-session-per-wcf-operation-the-easy-way/

https://github.com/haf/Castle.Facilities.NHibernate/wiki/NHibernate-Facility---Quick-Start

1 ответ

Во-первых, вы должны знать, что интерпретации Henrik Feldt Castle Castle и AutoTx Facility требуют использования атрибута [Transaction] (как я уже говорил с Mr.Feldt в списках рассылки Castle Users некоторое время назад).

Если вы хотите избавиться от атрибута [Transaction] от ваших классов обслуживания (для достижения POCO), но продолжаете использовать NH и WCF для сценария сеанса вызова, вам следует:

  1. Сохраните реализацию IServiceBehaviour, но добавьте интерфейс IDispatchMessageInspector в конструктор и назначьте его глобальному свойству класса IDispatchMessageInspector.

  2. В методе ApplyDispatchBehavior foreach ChannelDispatcher в serviceHostBase, зациклите конечные точки и добавьте внедренный экземпляр DispatchMessageInspector:

    foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
    {
        foreach (var endpoint in channelDispatcher.Endpoints)
        {
            endpoint.DispatchRuntime.MessageInspectors.Add(this.dispatchMessageInspector);
        }
    }
    
  3. Создайте класс, реализующий IDispatchMessageInspector (тот, который будет вставлен в предыдущий элемент). Давайте назовем этот класс NHWcfIntegrationMessageInspector.

  4. Вставьте ISessionFactory в NHWcfIntegrationMessageInspector и установите для него локальное свойство.

  5. В методе AfterRecieveRequest создайте объект сеанса NH с помощью ISessionFactory.Open(), начните транзакцию и привяжите этот сеанс к CurrentSessionContext.

  6. В методе BeforeSendReply отсоедините внедренный SessionFactory от CurrentSessionContext, который дает фактический объект сеанса. Проверьте, что транзакция активна из свойства Transaction сеанса и, если активно, Commit(), то это. Затем сессия Dispose().

  7. Не используйте INHibernateInstaller. Вместо этого используйте IWindsorInstaller и реализуйте его с MyHibernateInstaller. В блоке регистрации зарегистрируйте и свою реализацию IServiceBehavior, и свою новую реализацию IDispatchMessageInspector в контейнере.

  8. Также зарегистрируйте ISessionFactory в том же установщике и укажите метод конфигурации FNH как метод фабрики, но предоставьте встроенный ISessionFactory. Но в вашей конфигурации FNH перед сборкой ISessionFactory из вызова объекта fluentconfiguration:

    fluentConfiguration.CurrentSessionContext<WcfOperationSessionContext>();

  9. Та ДААА!

После выполнения этих шагов вам больше не нужно хранить ссылки на библиотеки Haf. Это чистый Замок. Ядро, Замок. Виндзор, NH/FNH.

Любые вопросы?;)

(извините за то, что я не публикую полный код, а просто описание, у меня есть контрактное обязательство)

Другие вопросы по тегам