.net 4.0 使用反应式扩展和计时器&引用;“为假人而设”;版本

.net 4.0 使用反应式扩展和计时器&引用;“为假人而设”;版本,.net-4.0,system.reactive,reactive-programming,.net 4.0,System.reactive,Reactive Programming,尽管社区提供了耐心的帮助,而且——我担心我还没有接近真正的理解。我正试图将这些概念灌输到我的大脑中,但我想解释一下亚瑟王的话:“这项新的研究让我困惑。请再解释一下关于羊的膀胱和地震。”在我看来,这正是我们可能正在谈论的 我将把它简化为需求(已经发生了变化,.NET 4.0是关键),而不是用我自己的(可能有缺陷的)实现走上错误的道路: 我需要使用.NET Framework 4.0来编写Windows服务 我需要我的Windows服务来调用web服务(WS),并将一个URL传递给它,但每次调用只传

尽管社区提供了耐心的帮助,而且——我担心我还没有接近真正的理解。我正试图将这些概念灌输到我的大脑中,但我想解释一下亚瑟王的话:“这项新的研究让我困惑。请再解释一下关于羊的膀胱和地震。”在我看来,这正是我们可能正在谈论的

我将把它简化为需求(已经发生了变化,.NET 4.0是关键),而不是用我自己的(可能有缺陷的)实现走上错误的道路:

  • 我需要使用.NET Framework 4.0来编写Windows服务
  • 我需要我的Windows服务来调用web服务(WS),并将一个URL传递给它,但每次调用只传递一个URL
  • 我需要能够为每个URL(1到n)定义单独的间隔来调用WS。例如:对于URL1,我可能每小时调用一次WS,对于URL2,我可能每四小时调用一次WS,等等
  • 如果某个特定URL的web服务返回错误,我需要能够停止调用该URL的web服务 就这样。据我所知,这是一个完美的接收方案。我很确定我想为序列创建
    Observable.Timer
    s,但是如何在出现错误时禁用计时器呢?这可能是一个等待发生的
    CancellationToken
    (或者我只是完成计时器),但我似乎无法将这些示例混合到一个可靠的、可理解的解决方案中

    有人想牵着这位老人的手,用小词解释做这种胡说八道的正确方法吗?如果我没有很好地解释它,或者如果我遗漏了什么,我会很乐意编辑它

    谢谢。

    1)我想你应该看看
    可观察的间隔<代码>可观察。计时器
    是一个单值序列,与之相反,
    可观察。间隔
    将在给定的间隔内持续产生值。如果对于每个项目/url,该轮询周期是恒定的,那么这可能就是您想要的

    2) 您可以将
    IEnumerable
    (URL)和
    IObservable
    (轮询事件)序列混合在一起

    3) 错误将终止序列。您可以通过将序列中的值投影(
    Select
    )到WebRequest的输出来利用这一点。如果WebRequest失败,序列将
    OnError
    ,异常将作为OnError负载传播

    慢慢地通过这个过程

    • 我们要获取URL/句点对的列表
    • 在给定的时间段轮询URL
    • 如果对某个URL的任何调用失败,请停止轮询该URL(并可能记录该URL)
    • 如果windows服务已停止,请停止轮询
    让我们首先处理一个要轮询的URL

    protected override void OnStart(string [] args)
    {
        var resource = new {Url="http://www.bing.com", Period=TimeSpan.FromMinutes(3)};
    
        var pollingSequence =  Observable.Interval(resource.Period)
                                         .Select(_=>Request(resource.Url));
        var subscription = pollingSequence.Subscribe(
                response=>Log(response),
                ex=>Log(ex)
            ));
        _subscriptions = new CompositeDisposable(subscription);
    }
    
    protected override void OnStop()
    {
        Dispose();
    }
    
    private bool Request(string url)
    {
        //TODO:
    }
    
    public void Dispose()
    {
        _subscriptions.Dispose();
    }
    
    为了将其可视化,我们可以使用“大理石图”。这里每个字符空间代表1分钟。OnNext表示为“o”(大理石)

    更准确地说,我们实际上是通过事件获取值(尽管我们忽略了值)

    然后,我们将每个事件投影到一个请求,因此序列现在转到这里(其中“r”表示来自请求的响应)

    如果任何请求失败,序列将终止。例如,这里3个请求失败,我们显示一个带有“X”的OnError

        bing    --r--r--X
    
    现在我们可以将示例扩展到资源列表,即
    IEnumerable

    接下来,我们考虑每一行也有轮询事件序列(时间数据)。根据上述代码(使用1个字符=1分钟)

    • 您不能订阅
      IEnumerable
      ,但有处理此类数据的接收方法,如Concat和Merge。 但是,我们不想使用这些,因为它们将序列展平为单个序列,这意味着如果任何序列失败,所有轮询都将停止

    我认为您需要将您的问题分解成更小的部分,以便人们帮助您解决。这对于一个答案来说太大了,尤其是在一个流量非常小的主题上(系统反应)。你认为
    n
    会有多大?@Brandon-
    n
    在我最疯狂的极端情况下不应该超过100个URL-最多可能是10个或20个。那么,Lee的解决方案就是这样。Lee,你太好了。感谢您花额外的时间为班上速度较慢的孩子解释这一点。;-)你能为轮询序列分解LINQ查询吗?我在概念化
    select
    .select()
    一起工作的方式时遇到问题。我已更新示例,以显示首先使用单个资源,然后扩展该示例使用资源列表。你是个了不起的老师。这太棒了,我希望它能像帮助我一样帮助社区的其他人。再次感谢。这段代码仍然“失败”,程序几乎立即停止。订阅
    新CompositeDisposable(订阅)
    不应该阻止这种情况发生吗?
        bing    --0--1--2--3-       
    
        bing    --r--r--r--r-       
    
        bing    --r--r--X
    
    protected override void OnStart(string [] args)
    {
        var resources = new[] { 
            new {Url="http://www.bing.com", Period=TimeSpan.FromMinutes(3)},
            new {Url="http://www.google.com", Period=TimeSpan.FromMinutes(2)},
            new {Url="http://www.yahoo.com", Period=TimeSpan.FromMinutes(5)},
            new {Url="http://www.stackoverflow.com", Period=TimeSpan.FromMinutes(2)}
        };
    
        //The same as before, but now we create a polling sequence per resource.
        var pollingSequences = from resource in resources
                            select Observable.Interval(resource.Period)
                                                .Select(_=>Request(resource.Url));
    
        //Now we cant subscribe to an `IEnumerable<IObservable<T>>` *, 
        //  but we can subscribe to each sequence in it.
        // This turns our queries (IE<IO<T>>) into subscriptions (IE<IDisposable>).
        var subscriptions = pollingSequences.Select(x => 
            x.Subscribe(
                response=>Log(response),
                ex=>Log(ex)
            ));
        _subscriptions = new CompositeDisposable(subscriptions);
    }
    
        bing
        google
        yahoo
        SO
    
        bing    --1--2--3-      (every 3rd minute)
        google  -1-2-3-4-5      (every 2nd minute)
        yahoo   ----1----2      (every 5 minutes)
        SO      -1-2-3-4-5      (every 2nd minute)