繁体   English   中英

使用Rx轮询网站

[英]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. 我把事情放在一起非常正确
  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));
    }
 }

可能给你太多(或错过了一些东西)!

谢谢

我想我有一个不错的起点。

基本上我认为你需要抽象出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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM