0

背景 私はカスタム ライブラリ (まだ公開されていませんが、すぐに) を使用して jQuery の JavaScript クライアントに長いポーリング ハンドラーを提供する ASP.net アプリケーションを作成しています。クライアントはハンドラーを呼び出し、ハンドラーが何らかのデータを返すまで待ち​​、それを表示してから、もう一度ハンドラーをヒットします... 洗浄、すすぎ、繰り返します。

ハンドラーの仕事は、リクエストを受け取り、それをコレクション (通常はList<>) に入れ、データを含むイベントを待って、待機中のリクエストに返すことです。サーバーの静的クラス内の単純なイベントを使用してこれをテストしましたが、これはすべて正常に機能します。

問題 サーバー上のすべての AppDomains で、すべてのクライアントがメッセージを受信できるようにするために、単純な C# コンソール アプリを作成しました。これはバックグラウンドで実行され、WCF (NamedPipe) を介して DataContract を提供します。次に、WCF インターフェイスを介してコンソール アプリと通信できるクライアント オブジェクトを ASP.net に作成しました。

メッセージをキャッシュに同期的にプル/プッシュできます-これは正常に機能しています。ただし、WCF コントラクトで非同期パターンを使用しようとすると、EndMethod要求する前に、IAsyncResult を BeginMethod に返した直後に起動されます。

何が悪いのかわかりません.Googleには弱い例を示すリソースがたくさんありますが、役に立ちません.

私が望むの は、とにかくデータ コントラクトを介して WCF 経由でイベントにバインドすることですか? そうすれば、イベントにアタッチするだけで完了できます。キャッシュへの新しいメッセージによってイベントがトリガーされ、非同期ハンドラーがトリガーされて、待機中のすべてのリクエストが返されます。

これは可能ですか?もしそうなら、誰かがサンプル/チュートリアル/例を持っていますか?

従うべきコード...

4

1 に答える 1

2

私はこれを行ったのでこれが可能であることを知っており、これに関する情報が限られていることを知っています (私はすぐにブログ投稿を作成する予定です)。Subscribe/Unsubscribe基本的に、ポートを開いたままにする WCF メソッドを作成する必要があります。

サーバー コードは次のようになります。

[ServiceContract(SessionMode = SessionMode.Required,
    CallbackContract = typeof(IProcessorCallBack))]
public interface IProcessor
{
    [OperationContract]
    Boolean SubscribeToEvents();

    [OperationContract]
    Boolean UnsubscribeToEvents();
}

public interface IProcessorCallBack
{
    [OperationContract(IsOneWay = true)]
    void OnEvent(EventArgs args);
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class DDSpeechMikeProcessor:IProcessor
{
    private readonly List<IProcessorCallBack> _eventListeners = 
        new List<IProcessorCallBack>();

    public bool SubscribeToEvents()
    {
        var listenerToCallBacks =    
            OperationContext.Current.GetCallbackChannel<IProcessorCallBack>();
        if(!_eventListeners.Contains(listenerToCallBacks))
            _eventListeners.Add(listenerToCallBacks);
    }

    public bool UnsubscribeToEvents()
    {
        var listenerToCallBacks = 
            OperationContext.Current.GetCallbackChannel<IProcessorCallBack>();
        if (_eventListeners.Contains(listenerToCallBacks))
            _eventListeners.Remove(listenerToCallBacks);
    }

    //This is your server listening for the main event
    //which it will pass on to all listeners
    void OnEvent(EventArgs args)
    {
        foreach(var listener in _eventListeners)
        {
            try
            {
                listener.OnEvent(args);
            }
            catch (Exception exception)
            {
                RemoveListenerIfBadCommunication(listener, exception);
            }
        }
    }

    //If a listener did not unsubscribe before shutting down you will get exceptions
    private void RemoveListenerIfBadCommunication(IProcessorCallBack listener, 
        Exception exception)
    {
        if (exception.GetType() == typeof(CommunicationException)
            || exception.GetType() == typeof(CommunicationObjectAbortedException)
            || exception.GetType() == typeof(CommunicationObjectFaultedException)
        )
           _eventListeners.Remove(listener);
    }
}

クライアント コードで:

public class Client : IProcessorCallBack
{
    DuplexChannelFactory<IProcessor> _processorFactory;
    IProcessor _processor
    void OpenProcessor()
    {
        _speechMikeProcessorFactory = new DuplexChannelFactory<IProcessor>(
              this,
              new NetNamedPipeBinding(),
              new EndpointAddress(baseUri + @"/" + HostName));
        _processor = _speechMikeProcessorFactory.CreateChannel();
        _processor.SubscribeToEvents();
    }

    void OnEvent(EventArgs args)
    {
         //Do Stuff
    }
}

もっと詳しく説明する必要がある場合は教えてください

于 2012-06-20T15:39:54.150 に答える