1

我正在尝试第一次在 Wcf 服务中使用 Windsor NHibernate Facility 并替换当前手动注册 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 设施的集成

我已经下载了0.3.1.2001 工件并使用下面的资源尝试插入该工具并移除任何手动连接到 NHibernate 的线路。但是我不想用TransactionalandTransaction属性来装饰服务和方法。以下是我目前的线材。

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)
    {
    }
}

每当我调用服务端点之一时,服务都会失败,并出现以下异常:

尝试为解析类型“Juice.iCheque.eMoneySystem.Settlement.ISettlementService”实例化模型“NHibernate.ISession”时,上下文中没有事务。如果您已验证您的调用堆栈包含具有 [Transaction] 属性的方法,那么还要确保您已注册 AutoTx Facility。

问题是我如何在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---快速入门

4

1 回答 1

1

首先,您应该知道 Henrik Feldt 的 Castle Transactions 和 AutoTx Facility 解释需要使用 [Transaction] 属性(正如我前段时间在 Castle Users 邮件列表中与 Mr.Feldt 讨论过的那样)。

如果您想从服务类中删除 [Transaction] 属性(以实现 POCO),但在每个呼叫会话场景中继续使用 NH 和 WCF,您应该:

  1. 保留您的 IServiceBehaviour 实现,但在构造函数中注入 IDispatchMessageInspector 接口,并将其分配给类全局 IDispatchMessageInspector 属性。

  2. 在 serviceHostBase 中的每个 ChannelDispatcher 的 ApplyDispatchBehavior 方法中,循环端点并添加注入的 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 方法中使用 ISessionFactory.Open() 创建一个 NH 会话对象,开始事务并将该 ISession 绑定到 CurrentSessionContext

  6. 在 BeforeSendReply 方法中,从 CurrentSessionContext 中取消绑定注入的 SessionFactory,这将为您提供实际的会话对象。从会话的 Transaction 属性检查事务是否处于活动状态,如果处于活动状态则 Commit() 它。然后 Dispose() 会话。

  7. 不要使用 INHibernateInstaller。而是使用 IWindsorInstaller 并使用 MyHibernateInstaller 实现它。在注册块中,将您的 IServiceBehavior 实现和新的 IDispatchMessageInspector 实现注册到容器。

  8. 还要在同一安装程序中注册 ISessionFactory 并将 FNH 配置方法作为工厂方法提供,但提供已构建的 ISessionFactory。但是在从 fluentconfiguration 对象调用构建 ISessionFactory 之前的 FNH 配置中:

    fluentConfiguration.CurrentSessionContext<WcfOperationSessionContext>();

  9. 达达!

完成这些步骤后,您不必再持有对 Haf 库的引用。其纯粹的 Castle.Core、Castle.Windsor、NH/FNH。

任何问题?;)

(抱歉没有发布完整的代码,只是描述,我有合同义务)

于 2012-08-15T14:31:48.767 回答