2012-08-13 223 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