0

Rxについて頭を悩ませようとしているだけです

Rx を使用して 2 秒ごとに Web サイトをポーリングしています

var results = new List<MyDTO>();
var cx = new WebserviceAPI( ... );
var callback = cx.GetDataAsync().Subscribe(rs => { results.AddRange(rs); });
var poller = Observable.Interval(TimeSpan.FromSeconds(2)).Subscribe( _ => { cx.StartGetDataAsync(); });

(Web サービス API は、observable を作成する getItemsAsync/getItemsCompleted イベント ハンドラー タイプのメカニズムを公開します)。

Web サイトが戻ってきたら、応答の「ビジネス部分」を DTO の IEnumerable にアンパックしています。

public IObservable<IEnumerable<MyDTO>> GetDataAsync()
{
    var o = Observable.FromEventPattern<getItemsCompletedEventHandler,getItemsCompletedEventArgs>(
        h => _webService.getItemsCompleted += h,
        h => _webService.getItemsCompleted -= h);

    return o.Select(c=> from itm in c.EventArgs.Result.ItemList
                        select new MyDTO()
                        {
                           ...
                        });
}

私の推論は、すべてのデータが文字列内にあることを考えると、そこにパックして IEnumerable にすることは理にかなっているということです...しかし、それが正しいかどうかはわかりません!

Web サイトの応答に 2 秒以上かかる場合は、MSTest がクラッシュしていることがわかります。デバッグ時に生成されるエラーは

「非同期処理中にエラーが発生しました。複数の非同期同時操作を未処理にするには、一意の状態オブジェクトが必要です」

内部例外あり

「アイテムは既に追加されています。辞書のキー: 'System.Object' 追加中のキー: 'System.Object'」

問題は、前の呼び出しがデータの入力を完了する前に次の呼び出しが開始され、データが返されるという再入可能性の 1 つであると想定しています。

だからかどうかはわかりません

  1. 私は物事を非常に正しくまとめました
  2. 再入を避けるために、何らかの方法で接続を調整する必要があります。
  3. IEnumerable の代わりに別の中間データ構造 (またはメカニズム) を使用する必要があります

いくつかのガイダンスをいただければ幸いです。

編集 1: Web 呼び出しを変更して、一意の状態オブジェクトを含めるようにしました

public void StartGetDataAsync()
{
    ...
    //  was: _webService.getItemsAsync(request);
    _webService.getItemsAsync(request, Guid.NewGuid());
}

そしてそれを機能させました。しかし、それが正しい方法であるかどうかはまだわかりません

編集 2 - Web サービス sigs: webServiceApi クラスがラップする SOAP Web サービスを使用しています。作成された references.cs には、次のメソッドが含まれています。

public void getItemsAsync(GetItemsReq request, object userState) 
{
    if ((this.getItemsOperationCompleted == null)) 
    {
        this.getItemsOperationCompleted = new System.Threading.SendOrPostCallback(this.OngetItemsOperationCompleted);
    }
    this.InvokeAsync("getItems", new object[] {
                    request}, this.getItemsOperationCompleted, userState);
}

private System.Threading.SendOrPostCallback getItemsOperationCompleted;

public event getItemsCompletedEventHandler getItemsCompleted;

public delegate void getItemsCompletedEventHandler(object sender, getItemsCompletedEventArgs e);

public partial class getItemsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs 
{
    ...
}

private void OngetItemsOperationCompleted(object arg) 
{
    if ((this.getItemsCompleted != null)) 
    {
        System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
        this.getItemsCompleted(this, new getItemsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
    }
 }

おそらく与えすぎた(または何かを逃した)でしょう!

どうも

4

2 に答える 2

1

私はあなたのためにまともな出発点を持っていると思います.

基本的に、Web サービスの複雑さを抽象化し、結果を得るためにきれいな関数を作成する必要があると思います。

次のようなことを試してください:

Func<GetItemsReq, IObservable<getItemsCompletedEventArgs>> fetch =
    rq =>
        Observable.Create<getItemsCompletedEventArgs>(o =>
        {
            var cx = new WebserviceAPI(/* ... */);
            var state = new object();
            var res =
                Observable
                    .FromEventPattern<
                        getItemsCompletedEventHandler,
                        getItemsCompletedEventArgs>(
                        h => cx.getItemsCompleted += h,
                        h => cx.getItemsCompleted -= h)
                    .Where(x => x.EventArgs.UserState == state)
                    .Take(1)
                    .Select(x => x.EventArgs);
            var subscription = res.Subscribe(o);
            cx.getItemsAsync(rq, state);
            return subscription;
        });

個人的には、さらに一歩進んで戻り値の型を定義します。たとえばGetItemsReq、ユーザー状態オブジェクトは含まれませんが、基本的には と同じgetItemsCompletedEventArgsです。

Observable.Intervalその後、必要なポーリングを作成するために使用できるはずです。

Web サービスが実装しているIDisposable場合は、上記の関数に呼び出しを追加しObservable.Usingて、完了時に Web サービスを正しく破棄する必要があります。

これが役立つかどうか教えてください。

于 2012-05-24T04:33:20.200 に答える