如何在Rx中处理多个事件(具有依赖性)

时间:2011-09-14 09:38:23

标签: wcf events silverlight-4.0 system.reactive

我有几个WCF调用,比如A,B,C,D,E。它们在SL应用程序中(所以我想我必须小心线程等)。
我希望B在A完成后运行,而C可以​​与它们并发运行。我希望D在所有三个完成之后运行。另外基于一个条件(简单的如果......)我也想要E运行(与上述任何一个同时发生)。

我刚刚下载了Rx,觉得它是这项工作的工具。但是,我还没有掌握所有的操作员和技巧等。

可以这样做吗?怎么样?请解释为此所需的操作员。

编辑添加:为简单起见,我们假设所有这些服务都将字符串(或int)作为参数,并返回实现复杂接口的内容,因此事件很简单EventHandlers (非泛型),我将它们转换为处理程序代码中的特殊接口 一些输入在开始时可用,一些来自先前服务的结果(例如,B的输入字符串是根据A的结果计算的)

1 个答案:

答案 0 :(得分:2)

我已将编辑考虑在内并制定了解决方案。

我不得不说微软在Silverlight中编写简单的WCF调用非常困难。处理事件以从异步调用中获取返回数据真是太痛苦了。

话虽如此,通过一些“复制并粘贴”的样板代码,Rx可以很好地消除复杂性。

以下是我提出的最终客户端代码:

        var service = new Service1Client();

        var abs =
            from a in service.AObservable("a")
            from b in service.BObservable(a)
            select new { a, b };

        var cs = service.CObservable("c");

        var abcs = abs.Zip(cs, (ab, c) => new { ab.a, ab.b, c });

        var ds =
            from abc in abcs
            from d in service.DObservable(abc.a, abc.b, abc.c)
            select String.Format(
                "A={0} B={1} C={2} D={3}",
                abc.a, abc.b, abc.c, d);

        var condition = true;

        var es = from e in condition
                    ? service.EObservable("e")
                    : Observable.Empty<string>()
                 select String.Format("E={0}", e);

        ds.Merge(es).ObserveOnDispatcher()
                    .Subscribe(r => this.label1.Content += " " + r);

一方面,这段代码并不像我希望的那么漂亮,但另一方面,我认为我不能让它变得更好。希望你能看到你的要求是如何得到满足的。

现在有了坏消息 - 必须为每个服务代理创建扩展方法。定义EventArgs的方式无法在不使用特定服务引用类作为扩展方法的this参数的情况下获得结果。

从好的方面来看,虽然代码主要是“复制并粘贴”,但很少有修改。

此外,您需要创建与您使用的参数一样多的扩展方法以及一个。

以下是我需要为示例代码定义的扩展方法:

public static class Service1ClientEx
{
    public static Func<IObservable<R>> ToObservableFunc<EA, R>(this Service1Client service, Action<Service1Client> async, Action<Service1Client, EventHandler<EA>> ah, Action<Service1Client, EventHandler<EA>> rh, Func<EA, R> resultSelector)
        where EA : System.ComponentModel.AsyncCompletedEventArgs
    {
        return () => Observable.Create<R>(o =>
        {
            var response =
                from ep in Observable.FromEventPattern<EA>(h => ah(service, h), h => rh(service, h))
                select resultSelector(ep.EventArgs);

            var subscription = response.Take(1).Subscribe(o);

            async(service);

            return subscription;
        }).ObserveOn(Scheduler.ThreadPool);
    }

    public static Func<P0, IObservable<R>> ToObservableFunc<P0, EA, R>(this Service1Client service, Action<Service1Client, P0> async, Action<Service1Client, EventHandler<EA>> ah, Action<Service1Client, EventHandler<EA>> rh, Func<EA, R> resultSelector)
        where EA : System.ComponentModel.AsyncCompletedEventArgs
    {
        return p0 => Observable.Create<R>(o =>
        {
            var response =
                from ep in Observable.FromEventPattern<EA>(h => ah(service, h), h => rh(service, h))
                select resultSelector(ep.EventArgs);

            var subscription = response.Take(1).Subscribe(o);

            async(service, p0);

            return subscription;
        }).ObserveOn(Scheduler.ThreadPool);
    }

    public static Func<P0, P1, IObservable<R>> ToObservableFunc<P0, P1, EA, R>(this Service1Client service, Action<Service1Client, P0, P1> async, Action<Service1Client, EventHandler<EA>> ah, Action<Service1Client, EventHandler<EA>> rh, Func<EA, R> resultSelector)
        where EA : System.ComponentModel.AsyncCompletedEventArgs
    {
        return (p0, p1) => Observable.Create<R>(o =>
        {
            var response =
                from ep in Observable.FromEventPattern<EA>(h => ah(service, h), h => rh(service, h))
                select resultSelector(ep.EventArgs);

            var subscription = response.Take(1).Subscribe(o);

            async(service, p0, p1);

            return subscription;
        }).ObserveOn(Scheduler.ThreadPool);
    }

    public static Func<P0, P1, P2, IObservable<R>> ToObservableFunc<P0, P1, P2, EA, R>(this Service1Client service, Action<Service1Client, P0, P1, P2> async, Action<Service1Client, EventHandler<EA>> ah, Action<Service1Client, EventHandler<EA>> rh, Func<EA, R> resultSelector)
        where EA : System.ComponentModel.AsyncCompletedEventArgs
    {
        return (p0, p1, p2) => Observable.Create<R>(o =>
        {
            var response =
                from ep in Observable.FromEventPattern<EA>(h => ah(service, h), h => rh(service, h))
                select resultSelector(ep.EventArgs);

            var subscription = response.Take(1).Subscribe(o);

            async(service, p0, p1, p2);

            return subscription;
        }).ObserveOn(Scheduler.ThreadPool);
    }

    public static Func<P0, P1, P2, P3, IObservable<R>> ToObservableFunc<P0, P1, P2, P3, EA, R>(this Service1Client service, Action<Service1Client, P0, P1, P2, P3> async, Action<Service1Client, EventHandler<EA>> ah, Action<Service1Client, EventHandler<EA>> rh, Func<EA, R> resultSelector)
        where EA : System.ComponentModel.AsyncCompletedEventArgs
    {
        return (p0, p1, p2, p3) => Observable.Create<R>(o =>
        {
            var response =
                from ep in Observable.FromEventPattern<EA>(h => ah(service, h), h => rh(service, h))
                select resultSelector(ep.EventArgs);

            var subscription = response.Take(1).Subscribe(o);

            async(service, p0, p1, p2, p3);

            return subscription;
        }).ObserveOn(Scheduler.ThreadPool);
    }

    public static IObservable<string> AObservable(this Service1Client service, string data)
    {
        return service
            .ToObservableFunc<string, ACompletedEventArgs, string>((s, p0) => s.AAsync(p0), (s, h) => s.ACompleted += h, (s, h) => s.ACompleted -= h, ea => ea.Result)
            .Invoke(data);
    }

    public static IObservable<string> BObservable(this Service1Client service, string data)
    {
        return service
            .ToObservableFunc<string, BCompletedEventArgs, string>((s, p0) => s.BAsync(p0), (s, h) => s.BCompleted += h, (s, h) => s.BCompleted -= h, ea => ea.Result)
            .Invoke(data);
    }

    public static IObservable<string> CObservable(this Service1Client service, string data)
    {
        return service
            .ToObservableFunc<string, CCompletedEventArgs, string>((s, p0) => s.CAsync(p0), (s, h) => s.CCompleted += h, (s, h) => s.CCompleted -= h, ea => ea.Result)
            .Invoke(data);
    }

    public static IObservable<string> DObservable(this Service1Client service, string dataA, string dataB, string dataC)
    {
        return service
            .ToObservableFunc<string, string, string, DCompletedEventArgs, string>((s, p0, p1, p2) => s.DAsync(p0, p1, p2), (s, h) => s.DCompleted += h, (s, h) => s.DCompleted -= h, ea => ea.Result)
            .Invoke(dataA, dataB, dataC);
    }

    public static IObservable<string> EObservable(this Service1Client service, string data)
    {
        return service
            .ToObservableFunc<string, ECompletedEventArgs, string>((s, p0) => s.EAsync(p0), (s, h) => s.ECompleted += h, (s, h) => s.ECompleted -= h, ea => ea.Result)
            .Invoke(data);
    }
}
像我说的那样痛苦。

你当然不必创建这些类型的扩展方法来在Silverlight中使用Rx和WCF,但我觉得一旦你创建了它们,那么客户端代码变得更容易使用。

如果您需要更多解释,请告诉我。