2012-08-13 224 views
3

我想编写一个库,可以与Web服务器进行通信并将数据从其中泄露给世界其他地方。 Web服务器没什么特别的,它暴露了几个REST方法,主要是GET和POST。IObservable REST客户端

由于我对Reactive Extensions相对较新(但我已经喜欢它),所以我征求了建议。我决定库的接口将暴露IObservables。但我不知道如何实现这一点。我想我有几个选择:

1)公开IObservable<IEnumerable<T>>。有意义的是,REST服务一次返回所有请求的数据。用户调用Subscribe(),只推送一个IEnumerable,调用OnDone。所以Subscribe()需要被多次调用。

2)公开IObservable<T>。在某些情况下,我猜可能是一个不错的选择。订阅()只会被调用一次,以获取其他数据,将有方法Refresh()或NextPage()(...)以获取更多数据流。 (当时不是IObservable<T> GetResource...它可能是一个属性,IObservable<T> Resource { get; }

3)忘记的Rx,通过事件(最糟糕的事情IMO)

4)一些其他的方式做到这一点老式方法?

有这方面经验的人吗?我所关心的是刷新(要求提供新数据),Paging,结合结果并且通常具有良好的可维护性设计。

THX的任何意见

回答

2

我会建议使用以下接口:

public interface IRestService 
{ 
    IObservable<T> GetResources<T>(); 
} 

有许多的这种选择背后的原因。

若要公开IObservable<IEnumerable<T>>融合了互动媒体reactives(或可观察与可枚举),并会迫使你的查询调用.ToObservable(),或者更糟糕,.ToEnumerable()构建基本SelectMany查询。最好让你的查询和订阅代码更好干净。

现在,您建议使用IObservable<T>,您只需订阅一次,并且您需要调用RefreshNextPage以获取更多数据流。这不是一个好主意。您应该想到单个订阅会返回单个REST调用的所有结果,然后致电OnComplete。如果你想调用一个新的REST调用,那么只需再次订阅。

此外,单个订阅调用的语义都没有明确的代码表示。所以你需要考虑维护你的代码。当你在将来看代码时,你可能会认为语义是什么?我建议单个订阅的语义映射到单个REST调用将更有可能。否则,您的代码可能会变得更加混乱。

更进一步,你应该避免单一的订阅模式,因为如果任何异常被抛出,然后你观察到的完成,当然,调用Web服务可以非常容易出错。如果您在多订阅模式中出错,您可以更轻松地恢复。

我也会避免IObservable<T> Resources { get; },因为它建议某种“固定”值,而不是更动态 - 换句话说,每次调用都可能会给你不同的值。最好调用GetResources方法而不是Resources属性。

一些,底线,我有一个IObservable<T>抽象到您的基础REST服务的单个调用。

+0

是的,但是Rx的整个想法是否只有一个订阅并将数据推送给调用者?不得不每次都订阅以获得结果不会很反应.. – 2012-08-15 13:55:48

+0

@TomášBezouška - 我认为你错过了关于可组合性的观点。你可能会点击一个按钮或一个计时器,你想发起对Web服务的调用,所以你只需将它们变成观察对象,然后创建一个查询,以任何你喜欢的方式组合所有内容。重要的部分是每个部分执行基本操作,然后整个查询可以是强大的。有道理? – Enigmativity 2012-08-15 14:16:57

+0

好了,让方法Refresh()等会打破这种可组合性,对吧?我想我明白了,thx的澄清。 – 2012-08-15 16:57:15

0

你在这里结合两个问题这确实应该分开处理。

首先是您的代码将从其他来源获取数据。第二种是在有新数据可用时将数据发布给感兴趣的各方。

关于第一个,Reactive Extensions不会帮助。您的关注点在于定时获取数据;它必须是一个定时的时间间隔,因为在你的代码中调用REST服务时,没有回调,你没有什么可以挂钩的服务可以调用。

如果有某种回调到你的代码从外部服务,然后可以打包一些IObservable<T> implementation然后你可以订阅并执行您的操作(只是转发认购,真) 。

对于第一个问题,您可以使用无功扩展的唯一方法是使用Observable class上的静态Timer method来启动定时器。

对于第二个问题(你有你的数据,你要通知用户后),你绝对可以应该使用IObservable<T>执行通知用户。

在这种情况下,我强烈建议您不要试图从Subscribe methodIObservable<T>接口上的意图偏离。你应该公开一个方法,该方法将给你IObservable<T>任何人都可以订阅(无论IObservable<T>是热还是冷,在调用Subscribe由你决定之前),并通过调用Dispose method从调用返回的IDisposable interface实现取消订阅到Subscribe

这样一来,你的客户可以得到IObservable<T>,认购自己想要的通知,然后他们就完成当退订。

+0

关于Rx没有用的下载内容 - 有一个我认为很有用的场景 - 一次获取多个资源(使用多余的休息请求),然后通知完成。 ForkJoin在这里显然是赢家。你怎么看? – 2012-08-14 17:25:27

+0

@TomášBezouška我没有说它下载的东西没有什么用处,相反,它可能会揭示你下载的内容。大多数网络库不会返回'IObservable ''实现,所以你通常没有那么奢侈,并且你没有表明你在你的问题中做过。 – casperOne 2012-08-14 17:30:36