[英]Polling a website using Rx
只是試圖讓我的頭圍繞Rx
我每隔2秒使用Rx來瀏覽一個網站
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(); });
(webservice API公開了一個getItemsAsync / getItemsCompleted事件處理程序類型機制,我正在從中創建一個observable)。
當網站返回時,我正在將響應的“業務部分”解壓縮到IEnumerable的DTO中
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中才有意義......但現在我不確定這是不對的!
如果網站響應時間超過2秒,我發現MSTest正在崩潰。 調試時,生成的錯誤是
“異步處理期間出現錯誤。多個異步同步操作需要獨特的狀態對象才能出色”
內在的例外
“項目已被添加。鍵入字典:'System.Object'鍵被添加:'System.Object'”
我假設問題是重入的問題之一是下一個調用是在前一個調用完成填充數據之前啟動並返回數據。
所以我不確定是否
我會很感激一些指導。
編輯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));
}
}
可能給你太多(或錯過了一些東西)!
謝謝
我想我有一個不錯的起點。
基本上我認為你需要抽象出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服務完成時正確處理它。
如果這有幫助,請告訴我。
Enigmativity有一個很好的解決方案。
var state = new object(); cx.getItemsAsync(rq, state);
這些陳述是解決錯誤的關鍵。
每次調用Async方法時,都需要傳遞一個唯一的對象(除非當然只有一個Async方法一次運行,這是非常不可能的)。 我抓了幾個小時,直到我發現你可以傳遞一個對象參數。 如果沒有參數,它將看到多個方法作為同一個調用,並為您提供“已添加項目。鍵入字典:'System.Object'鍵被添加:'System.Object'”消息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.