7
  • WCF サービスを作成する Windows サービス アプリケーションがあります。
  • サービスの 1 つはデータ サービスです。WCF を介してデータを追加、削除、読み取り、更新します。
  • WCFはデータ操作にNHibernateを使用します

だから私のゲストは:

  • WCF で使用する Hibernate のセッション管理に関するアドバイス (ベスト プラクティス) はありますか?

  • 誰でも何でも知っている

WcfOperationSessionContext (休止状態 3.0) クラス?

how to use it with WCF?

それを具体的にするために:

DataServicesと呼ばれる WCF サービスがあるとします。

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: ここや他の Web ページで同様のエントリを読みました。しかし、「具体的な」答えは見えません。

4

4 に答える 4

9

ThreadStaticSessionContext および WebRequestSessionContext と同様の WcfOperationSessionContext は、セッション コンテキストの実装です。セッション コンテキストは、ISession インスタンスを特定のコンテキストにバインド (関連付け) するために使用されます。

現在のコンテキストのセッションは、ISessionFactory.GetCurrentSession() を呼び出すことで取得できます。

セッション コンテキストの詳細については、こちらを参照してください。

WcfOperationSessionContext は、WCF 操作の全期間にわたるコンテキストを表します。操作の開始時にセッションのバインドを処理し、操作の最後にセッションのバインド解除/コミット/破棄を処理する必要があります。

wcf パイプラインで開始/終了アクションにアクセスするには、IDispatchMessageInspector を実装する必要があります。ここでサンプルを見ることができます。

また、WCF 統合に関して: ThreadStatic セッション コンテキストを使用すると、開発では機能するように見えますが、wcf パイプラインからのさまざまなコンポーネント (承認、認証など) が異なるスレッドで実行されると、本番環境で壁にぶつかります。

ベスト プラクティスについては、ほぼ完璧です。WcfOperationSessionContext を使用して現在のセッションを保存し、IDispatchMessageInspector を使用して作業単位を開始/完了します。

編集 - 追加した詳細に対処するには: WcfOperationSessionContext を構成し、上記で説明したようにバインディング/アンバインディングを行う場合、ISessionFactory をサービスに挿入し、factory.GetCurrentSession() を使用するだけです。時間が許せば、サンプル prj を投稿します。

サンプルプロジェクトはこちら

于 2011-03-22T15:07:08.230 に答える
5

WCF で NHibernate セッションを管理するために使用するモデルは次のとおりです。

1) ICallContextInitializer も実装する System.ServiceModel.ServiceHost から継承する独自の ServiceHost クラスがあります。次のように、サービスの各操作にサービス ホスト インスタンスを追加します。

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 は、各 WCF 呼び出しの OperationContext に独自のセッションがあることを確認するだけです。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 操作が完了すると破棄されることが保証されます。必要に応じて、通常の方法でトランザクションを使用できます。

于 2011-03-23T05:35:03.307 に答える
3

これは、WcfOperationSessionContext を登録して使用するためのすべての手順を詳細に説明した投稿ですまた、agatha-rrsl プロジェクトで使用するための手順も含まれています。

于 2011-03-30T16:42:26.967 に答える
1

さて、インターネットの投稿などを数日読んだ後、インターネットに表示されているすべてのアプローチは間違っているようです。NH 3 ^でUnitOfWorkパターンを使用し、nhibernateトランザクションを使用している場合、このすべてのアプローチで例外が発生します。それをテストし、MSMQトランザクションキューを使用してテスト環境を作成する必要があることを証明するために、トランザクションが必要なOneWay操作コントラクトとの特別なインターフェイスが設定されています。このアプローチは次のように機能するはずです。1。トランザクションメッセージをキューに入れます。2.サービスがキューからトランザクションメッセージを取得しています。3.すべての作業キューが空です。

場合によっては、インターネットのアプローチにそれほど従わない場合、これは適切に機能しません。それで、ここに私たちがテストした間違った例とその理由があります:

  1. Fabio Mauloのアプローチ:ICallContextInitializerを使用します-BeforeCallでNHセッション/トランザクションを開きます。その後、WCFがサービスメソッドを実行し、コンテキスト初期化子のAfterCallでsession.Flush+transaction.commitを呼び出します。トランザクションスコープが操作をコミットすると、セッションが自動的に保存されます。トランザクションを呼び出すときの状況。完全な例外がスローされます。WCFサービスはシャットダウンします。質問は大丈夫かもしれないので、トランザクションを取ります。try/ catch節で完了します-素晴らしいです!- 何も間違っていません!次に、トランザクションスコープはトランザクションをコミットし、メッセージはキューから取得されますが、データは保存されません。
  2. もう1つのアプローチは、IDispatchMessageInspectorを使用することです。昨日、これが最善のアプローチだと思いました。ここでは、メッセージディスパッチャインスペクタのBeforeSendReplyが呼び出された後にWCFがサービス操作を呼び出した後、メソッドAfterReceiveRequestでセッション/トランザクションを開く必要があります。このメソッドには、OneWay操作ではnullである[reply]に関する情報がありますが、サービスメソッドの呼び出しで発生した場合は障害情報が入力されます。素晴らしいと思いました-これはこれです!だがしかし!問題は、WCF処理パイプのこの時点では、トランザクションがないことです。したがって、transaction.Completeがエラーまたはsession.Flushをスローすると、データベースにデータが保存されず、メッセージがキューに戻って何が問題になるかがわかりません。

解決策は何ですか?

IOperationInvokerとこれだけ!

このインターフェイスは、デフォルトの呼び出し側にデコレータパターンとして実装する必要があります。メソッドInvokebeforecallでは、セッション/トランザクションを開いています。次に、invoke default invokerを呼び出し、その後、transaction.completeを呼び出して、最後にsession.flushを呼び出します。これが解決する問題の種類:1。このレベルのトランザクションスコープがあるため、完全にスローされると、例外メッセージがキューに戻り、WCFがシャットダウンしません。2.呼び出しが例外transaction.completeをスローする場合、データベースの状態を変更しないものは呼び出されません

これにより、皆さんの誤報が解消されることを願っています。

自由な時間に、私はいくつかの例を書こうとします。

于 2013-03-16T15:31:06.000 に答える