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 までの手動ワイヤを削除しようとしました。Transactionalただし、サービスとメソッドをandTransaction属性で装飾したくありません。以下は私の現在の配線です。

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

サービス エンドポイントの 1 つを呼び出すたびに、サービスは次の例外で失敗します。

解決タイプ「Juice.iCheque.eMoneySystem.Settlement.ISettlementService」のモデル「NHibernate.ISession」をインスタンス化しようとすると、コンテキストにトランザクションがありません。コール スタックに [Transaction] 属性を持つメソッドが含まれていることを確認した場合は、AutoTx 機能が登録されていることも確認してください。

問題はNHibernateFacility、現在の実装で を使用し、Transaction属性を使用しない方法です。

資力

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

https://github.com/haf/Castle.Facility.NHibernate/wiki/NHibernate-Facility---クイックスタート

4

1 に答える 1

1

まず、Henrik Feldt の Castle Transactions と AutoTx Facility の解釈には [Transaction] 属性の使用が必要であることを知っておく必要があります (以前、Castle Users メーリング リストで Feldt 氏と話し合ったように)。

(POCO を達成するために) サービス クラスから [Transaction] 属性を取り除きたいが、呼び出しセッション シナリオごとに 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 メソッドで、挿入された SessionFactory を CurrentSessionContext からバインド解除します。これにより、実際のセッション オブジェクトが得られます。セッションの Transaction プロパティからトランザクションがアクティブであることを確認し、アクティブな場合は Commit() を実行します。次に Dispose() セッション。

  7. INHibernateInstaller を使用しないでください。代わりに IWindsorInstaller を使用し、MyHibernateInstaller で実装してください。登録ブロックで、IServiceBehavior 実装と新しい IDispatchMessageInspector 実装の両方をコンテナーに登録します。

  8. また、同じインストーラーに ISessionFactory を登録し、FNH 構成メソッドをファクトリ メソッドとして提供しますが、ビルドされた ISessionFactory を提供します。ただし、流暢な構成オブジェクト呼び出しから ISessionFactory を構築する前に、FNH 構成で:

    fluentConfiguration.CurrentSessionContext<WcfOperationSessionContext>();

  9. タダァァ!

これらの手順を完了すると、Haf のライブラリへの参照を保持する必要がなくなります。その純粋な Castle.Core、Castle.Windsor、NH/FNH。

質問は?;)

(完全なコードではなく説明だけを掲載して申し訳ありません。私は契約義務を負っています)

于 2012-08-15T14:31:48.767 に答える