読者です 読者をやめる 読者になる 読者になる

雑記 - otherwise

最近はDQ10しかやっていないダメ技術者がちまちまと綴る雑記帳

WebService から情報を取得するアプリケーションの作成 (2)

WindowsPhone

それでは実際に Rx を利用した Windows Phone アプリケーションでの Web アクセス処理について見ていきましょう。

Web アクセスプログラミングのキホン

Windows Phone アプリケーションではデスクトップ向けアプリケーションと同様に WebClient クラスや WebRequest / WebResponse クラスを使用して Web 上のリソースにアクセスする事ができます。
但し、ベースとなっている Silverlight と同様に、同期的なアクセスは出来ず全て非同期通信となります。
なお、 Silverlight では(完全信頼のアプリケーションを除いて)クロスドメインアクセスが出来ませんが、 Windows Phone アプリケーションではクロスドメインの制約はなく、基本的に全ての Web リソースへのアクセスが可能です。(接続先の Web リソース側で個別に制限を設けている場合を除きます)

AsynchronousExtensions を活用する

AsynchronousExtensions には、非同期で WebClient や WebRequest / WebResponse を使用するのに便利な拡張メソッドが数多く定義されています。
そのうちのいくつかを紹介しておきます。

WebClient
  • IObservable DownloadStringObservableAsync(string address)
  • IObservable DownloadStringObservableAsync(Uri address)
  • IObservable DownloadStringObservableAsync(Uri address, IProgress progressReporter)

URI を指定して Web リソースを文字列で取得します。
取得した結果は長さ 1 の Observable として返却されます。
第二引数に progressReporter を指定すると、ダウンロード進捗状況の捕捉が可能になります。(本記事では使用しませんが。。。)

  • IObservable UploadStringObservableAsync(string address, string data, string method = null)
  • IObservable UploadStringObservableAsync(Uri address, string data, string method = null)
  • IObservable UploadStringObservableAsync(Uri address, string data, IProgress progressReporter, string method = null)

URI を指定して文字列データを送信します。
送信結果は DownloadStringAsync と同じ様に長さ 1 の Observable として返却されます。

WebRequest
  • IObservable DownloadStringAsync()
  • IObservable DownloadStringAsync(Encoding encoding)
  • IObservable DownloadStringAsync(IProgress progressReporter)
  • IObservable DownloadStringAsync(Encoding encoding, IProgress progressReporter)

Web リソースを文字列で取得します。
取得した結果は WebClient の DownloadStringAsync と同様に長さ 1  の Observable として返却されます。
progressReporter を指定すると、ダウンロード進捗状況の捕捉が可能になります、

  • IObservable DownloadStringLineAsync()
  • IObservable DownloadStringLineAsync(Encoding encoding)

Web リソースを文字列で取得します。
DownloadString と違い、取得した結果を 1 行ずつ返却します。従って、返却される IObservable の長さは結果データの行数となります。

  • IObservable DownloadDataAsync()
  • IObservable DownloadDataAsync(IProgress progressReporter)

Web リソースをバイト列データで取得します。
取得した結果は長さ 1 の Observable として返却されます。

  • IObservable GetResponseObservableAsync()
  • IObservable GetResponseObservableAsync() (※ HttpWebRequest の拡張メソッド)

WebReponse を直接制御したい場合は長さ 1 の IObservable ( HttpWebRequest を使用する場合は IObservable )を返却するメソッドも用意されています。

  • IObservable UploadStringAsync(string data)
  • IObservable UploadStringAsync(string data, Encoding encoding)
  • IObservable UploadStringAsync(string data, IProgress progressReporter)
  • IObservable UploadStringAsync(string data, Encoding encoding, IProgress progressReporter)

文字列データを送信します。
送信結果は長さ 1 の Observable として返却されます。

  • IObservable UploadValuesAsync(IDictionary parameters)
  • IObservable UploadValuesAsync(IDictionary parameters, Encoding encoding)
  • IObservable UploadValuesAsync(IDictionary parameters, IProgress progressReporter)
  • IObservable UploadValuesAsync(IDictionary parameters, Encoding encoding, IProgress progressReporter)

キーと値のセットを送信します。
送信結果は長さ 1 の Observable として返却されます。

  • IObservable UploadDataAsync(byte[] data)
  • IObservable UploadDataAsync(byte[] data, IProgress progressReporter, int chunkSize = 65536)

バイト列データを送信します。
送信結果は長さ 1 の Observable として返却されます。

エラー対策

Windows Phone に限らず、携帯端末の通信は常に接続されている事が保証されないため、通信処理に対するエラー対策は必須と言えます。
非同期処理でのエラーハンドリングはなかなか面倒なものですが、 Rx ではこの点のサポートもされており、処理メソッドチェーンの一部としてエラー処理を記述する事ができます。

リトライ処理 (Retry)
  • Retry()
  • Retry(int retryCount)

メソッドチェーンの中で Retry を使用すると、前段の処理で発生した例外を捕捉して処理を再実行する事ができます。
「通信処理でタイムアウトが発生した場合に一定回数リトライを行う」と云った処理を非常に簡潔に書く事が可能です。
Retry メソッドの戻り値は IObservable なので、メソッドチェーンを切る事なく後続の処理を続けて記述できます。

例外捕捉処理 (Catch)
  • Catch()
  • Catch(IObservable second)
  • Catch(Func> handler)

メソッドチェーンの中で Catch を使用すると、前段の処理で例外が発生した場合に該当の例外を捕捉して後続の処理を続ける事ができます。
メソッドの引数として後続に流すダミー値を指定可能なため、リトライしても改善の見込みがない様な例外(対象のリソースが見つからない等) が発生した場合等に有用です。

タイムアウト処理 (Timeout)
  • Timeout(DateTimeOffset dueTime)
  • Timeout(TimeSpan dueTime)
  • Timeout(DateTimeOffset dueTime, IScheduler scheduler)
  • Timeout(DateTimeOffset dueTime, IObservable other)
  • Timeout(TimeSpan dueTime, IScheduler scheduler)
  • Timeout(TimeSpan dueTime, IObservable other)
  • Timeout(DateTimeOffset dueTime, IObservable other, IScheduler scheduler)
  • Timeout(TimeSpan dueTime, IObservable other, IScheduler scheduler)

前段の処理を一定時間で強制的に打ち切りたい場合、 Timeout メソッドが利用できます。
特に Windows Phone の Web アクセスはタイムアウトの時間を設定できないため、最悪接続先のサーバのタイムアウトまで永遠に待ってしまう恐れがあります。そのため、この Timeout メソッドはとても有用です。

例外の捕捉

メソッドチェーンの途中で例外を捕捉する場合は前述の各メソッドを利用できますが、 Subscribe メソッドの OnException パラメータを使用する事でメソッドチェーンの終端で捕捉する事も可能です。
但しこの場合、例外が発生した時点でメソッドチェーン内の後続処理は全て Abort されるので注意が必要です。