使用Reactive Extensions轮询Web服务并绑定最后的x个结果

 怺恆啲喏琂_615 发布于 2023-01-06 15:05

我正在尝试将Reactive Extensions(Rx)用于一个看似合适的任务,以特定间隔轮询Web服务并显示其最后的x结果.

我有一个Web服务,它向我发送我想要监视的工具的状态.我想以特定的速率轮询此工具,并在列表中显示已轮询的最后20个状态.

所以我的列表就像是服务结果的"移动窗口".

我正在使用Caliburn.Micro开发一个WPF应用程序,但我不认为这是非常相关的.

我到目前为止得到的是以下内容(只是我快速入侵的示例应用程序,我不打算在真实应用程序中的ShellViewModel中执行此操作):

public class ShellViewModel : Caliburn.Micro.PropertyChangedBase, IShell
{
    private ObservableCollection times;
    private string currentTime;

    public ShellViewModel()
    {
        times = new ObservableCollection();

        Observable
            .Interval(TimeSpan.FromSeconds(1))
            .SelectMany(x => this.GetCurrentDate().ToObservable())
            .ObserveOnDispatcher()
            .Subscribe(x =>
            {
                this.CurrentTime = x;
                this.times.Add(x);
            });
    }

    public IEnumerable Times
    {
        get
        {
            return this.times;
        }
    }

    public string CurrentTime
    {
        get
        {
            return this.currentTime;
        }
        set
        {
            this.currentTime = value;
            this.NotifyOfPropertyChange(() => this.CurrentTime);
        }
    }

    private async Task GetCurrentDate()
    {
        var client = new RestClient("http://www.timeapi.org");
        var request = new RestRequest("/utc/now.json");

        var response = await client.ExecuteGetTaskAsync(request);

        return response.Content;
    }
}

在视图中,我只有一个绑定到CurrentTime属性的标签和一个绑定到Times属性的列表.

我的问题是:

它不仅限于列表中的20个项目,因为我总是添加项目,ObservableCollection但我找不到更好的数据绑定方式

Interval不能像我想的那样工作.如果查询运行时间超过1秒,则将同时运行两个查询,我不希望这样做.我的目标是查询无限期地重复,但每秒的查询速度不超过1次.如果查询结束时间超过1秒,则应等待它完成并直接触发新查询.

第二次编辑:

下面的编辑是我愚蠢而且很困惑,它会不断触发事件,因为Interval是一种永不停止的东西.Brandon的解决方案是正确的,并按预期工作.

编辑:

根据Brandon的例子,我尝试在LinqPad中执行以下代码:

Observable
    .Merge(Observable.Interval(TimeSpan.FromSeconds(2)), Observable.Interval(TimeSpan.FromSeconds(10)))
    .Repeat()
    .Scan(new List(), (list, item) => { list.Add(item); return list; })
    .Subscribe(x => Console.Out.WriteLine(x))

我可以看到对控制台的写入每2秒发生一次,而不是每10次发生一次.因此重复不会等待Observable在重复之前完成.

1 个回答
  • 试试这个:

    // timer that completes after 1 second
    var intervalTimer = Observable
        .Empty<string>()
        .Delay(TimeSpan.FromSeconds(1));
    
    // queries one time whenever subscribed
    var query = Observable.FromAsync(GetCurrentDate);
    
    // query + interval timer which completes
    // only after both the query and the timer
    // have expired
    
    var intervalQuery = Observable.Merge(query, intervalTimer);
    
    // Re-issue the query whenever intervalQuery completes
    var queryLoop = intervalQuery.Repeat();
    
    // Keep the 20 most recent results
    // Note.  Use an immutable list for this
    // https://www.nuget.org/packages/microsoft.bcl.immutable
    // otherwise you will have problems with
    // the list changing while an observer
    // is still observing it.
    var recentResults = queryLoop.Scan(
        ImmutableList.Create<string>(), // starts off empty
        (acc, item) =>
        {
            acc = acc.Add(item);
            if (acc.Count > 20)
            {
                acc = acc.RemoveAt(0);
            }
    
            return acc;
        });
    
    // store the results
    recentResults
        .ObserveOnDispatcher()
        .Subscribe(items =>
        {
            this.CurrentTime = items[0];
            this.RecentItems = items;
        });
    

    2023-01-06 15:07 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有