連載
続・無償環境でSilverlight 2アプリを開発しよう!

第2回 Webサービスを利用するSilverlightアプリを作ろう

シグマコンサルティング 菅原 英治
2009/03/04
Page1 Page2 Page3

コード・ビハインド側コードのポイント

 ここでは、コード・ビハインド側のポイントについて解説します。コード・ビハインド側では、いかにしてSilverlightアプリから、Webサービスを呼び出すか、がポイントとなります。大きくWebClientクラスを利用する方法と、WCFサービスを参照する2つの方法があります。今回は、WebClientクラスを利用する方法を重点的に解説します。

異なるドメイン間(クロス・ドメイン)のアクセスに注意

 Silverlightアプリから、Webサービスを呼び出す際に、最も気を付けてなくてはならないことは、異なるドメイン間(クロス・ドメイン)でのアクセスです。まずは、そこから解説します。

 Silverlightでは、原則として、アプリがホストされているドメインとは異なるドメインへのアクセスが(正確にはプロトコル、ホスト、ポートが異なる場合のアクセスも)禁止されています。今回のサンプルでの簡単な例を、次の図に示します。

異なるドメインへアクセスできない例

 図示したとおり、今回のサンプルのように「http://www.atmarkit.co.jp」に配置したSilverlightアプリからは、プロトコル、ホスト、ポート、ドメインのいずれかが異なるアドレスで公開されるWebサービスにはアクセスできません。

 しかし、実際今回のサンプルでは、「http://www.atmarkit.co.jp」に配置されていたSilverlightアプリから、Geocoding APIやガソリン価格情報WEBサービスapiという異なるドメインのWebサービスを呼び出せています。その秘密は、ドメイン間ポリシー・ファイルにあります。

ドメイン間ポリシー・ファイルについて

 Silverlightでは、「ドメイン間ポリシー・ファイル」と呼ばれるファイルを利用することで、異なるドメイン間での通信が可能になります。Silverlightでは、次の2種類のドメイン間ポリシー・ファイルがサポートされます。

  • Silverlightドメイン間ポリシー(clientaccesspolicy.xml)
  • Flashドメイン間ポリシー(crossdomain.xml)

 Silverlightは、異なるドメイン間で通信する場合、まず、Silverlightドメイン間ポリシー(clientaccesspolicy.xml)を探し、それが見つからない場合は、Flashドメイン間ポリシー(crossdomain.xml)を探すという動作を行います。詳しくは、次のMSDNに記載されていますので、ご参照ください。

 なお、Flashドメイン間ポリシーとは、名前から分かるようにAdobe Flash用のポリシー・ファイルです。このサポートにより、Flash向けに提供されているWebサービスも、(サービス提供者が)何も変更することなしに、Silverlightアプリからそのまま使えるようになっています。

ドメイン間ポリシー・ファイルの利用時の注意点

 ドメイン間ポリシー・ファイルを利用するうえで、特に意識してほしいのは、「ドメイン間ポリシー・ファイルはサービスを提供する側に必要だ」ということです。ガソリン価格情報WEBサービスapiを利用したければ、「http://api.gogo.gs/」に、ドメイン間ポリシー・ファイルが必要になります。

ドメイン間ポリシー・ファイルを利用するうえでの注意
サービスを提供する側にドメイン間ポリシー・ファイルが必要である

 ドメイン間ポリシー・ファイルには、「自分のサーバで、どのドメインからのアクセスを許可するか」が定義されています。実際に次のアドレスをブラウザで開き、ガソリン価格情報WEBサービスapiのドメイン間ポリシー・ファイルを確認することができます。

http://api.gogo.gs/crossdomain.xml

 ガソリン価格情報WEBサービスapiでは、現在のところ、下記のよう定義されており、アクセスできるドメインを制限していない(すべてのアクセスを許可している)ことが確認できます。

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM
  "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-access-from domain="*" />
</cross-domain-policy>
ガソリン価格情報WEBサービスapiのドメイン間ポリシー・ファイル(http://api.gogo.gs/crossdomain.xml

 一方、Geocoding APIのドメイン間ポリシー・ファイルは、どのように定義されているでしょうか。

http://www.geocoding.jp/crossdomain.xml

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM
  "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-access-from domain="www.e-yokohama.net" />
  <allow-access-from domain="www.attractors.jp" />
  <allow-access-from domain="kagaku.gakken.jp" />
  <allow-access-from domain="stgkagaku.gakken.jp" />
</cross-domain-policy>
Geocoding APIのドメイン間ポリシー・ファイル(http://www.geocoding.jp/crossdomain.xml

 ドメイン間ポリシー・ファイルを確認すると、アクセスできるドメインが限定されていることが分かります。また、アクセスが許可されているドメインには「www.atmarkit.co.jp」がありません。しかし、今回のサンプルでは、ちゃんとGeocoding APIを呼び出せています。不思議ですね。そのなぞは、次のコード・ビハインド側コードの解説で解明します。

コード・ビハインド側コードの解説

 それでは、コード・ビハインド側コードの解説です。今回のサンプルの処理についてはすでにその概要(2つのWebサービスを呼び出す流れ)を解説したので、特に説明するまでもないですが、念のため、次の図を再掲します。

サンプルの概要(再掲)

Webサービスの代理呼び出し

 まずは、Geocoding APIを利用して、入力された住所から緯度/経度を取得するまでを解説しましょう。

 ダウンロードしたソース・ファイル「Page.xaml」のコード・ビハインド(VB:Page.xaml.vb、C#:Page.xaml.cs)を開いてください。[価格取得]ボタンを押したときに呼び出される価格取得処理のGetPriceメソッドに注目です。

' 価格取得処理
Private Sub GetPrice()
  ……略……

  ' Geocodingを代理呼び出しするGoogle App EngineのURL設定
  ' (住所をエンコードして渡す)
  Dim url As String = String.Format( _
    "http://wsproxy.appspot.com/?q={0}", _
    HttpUtility.UrlEncode(Me.textBoxAddress.Text))

  ……略……
End Sub
// 価格取得処理
private void GetPrice()
{
  ……略……

  // Geocodingを代理呼び出しするGoogle App EngineのURL設定
  // (住所をエンコードして渡す)
  string url = string.Format(
    "http://wsproxy.appspot.com/?q={0}",
    HttpUtility.UrlEncode(this.textBoxAddress.Text));

  ……略……
}
価格取得処理内の代理呼び出し(上:Page.xaml.vb、下:Page.xaml.cs)

 GetPriceメソッドでは、入力された住所をGeocoding APIのWebサービスに渡す必要があります。しかし、すでに述べたとおり、Geocoding APIでは、ドメイン間ポリシー・ファイルによりアクセスできるドメインが制限されているため、そのままではアクセスできません。

 そこで、このサンプルでは、Google App Engine上に、「http://wsproxy.appspot.com/」というGeocoding APIの代理呼び出しを行うWebアプリ(以下、プロクシ・アプリ)を構築し、それを利用することで、この問題を解決しています。

Google App Engineを利用したプロクシ・アプリ

 このプロクシ・アプリのソースは、こちらからダウンロードできます。ソースの説明は、本稿の範囲を外れますので避けますが、簡単にこのプロクシ・アプリを説明しましょう。

 プロクシ・アプリのあるWebサイトでは、アクセス制限のないドメイン間ポリシー・ファイルを公開しています。

http://wsproxy.appspot.com/crossdomain.xml

 これによって、Silverlightアプリから、このプロクシ・アプリへのアクセスが可能となります。また、Silverlightアプリから受け取った住所を、そのまま、Geocoding APIに渡し、緯度/経度を受け取ります。そして、受け取った緯度/経度をそのままSilverlightアプリに返すことで、結果としてGeocoding APIを呼び出すことに成功しています。

【コラム】Webサービスを代理で呼び出すそのほかの方法

 Webサービスを代理で呼び出すそのほかの方法として、WCFサービスを利用する方法があります。本文中のGoogle App Engineでのプロクシ・アプリの役割を、WCFサービスとして構築し、SilverlightアプリからはWCFサービスを呼び出すことで実現できます。

 この方法は、.NETのテクノロジで統一できるという点で非常によいのですが、1点だけ課題があります。それは、WCFサービスを利用するため、いざ実際にSilverlightアプリを公開しようとしたとき、WCFサービスをホスティングできる環境が限られてしまうということです。

 今回のサンプルのように、気軽にインターネット上で公開するには、本文中で紹介する方法が向いています。

WebClientクラスの利用

 WebClientクラスを利用したWebサービスの呼び出し方法は、非常に簡単です。次のコードをご覧ください。

' 価格取得処理
Private Sub GetPrice()
  ……略……

  ' GeocodingをWebClientで呼び出す
  Dim geocodingClient As New WebClient()
  AddHandler geocodingClient.DownloadStringCompleted, _
    AddressOf geocodingClient_DownloadStringCompleted
  geocodingClient.DownloadStringAsync(New Uri(url))

  ……略……
End Sub

' 座標取得完了時のイベント・ハンドラ
Sub geocodingClient_DownloadStringCompleted(ByVal sender As System.Object, ByVal e As DownloadStringCompletedEventArgs)

  ……略……

  '結果のXMLをパースする
  Dim rootElement As XElement = XElement.Parse(e.Result)

  ……略……

End Sub
// 価格取得処理
private void GetPrice()
{
  ……略……

  //GeocodingをWebClientで呼び出す
  WebClient geocodingClient = new WebClient();
  geocodingClient.DownloadStringCompleted
    += geocodingClient_DownloadStringCompleted;
  geocodingClient.DownloadStringAsync(new Uri(url));

  ……略……
}

// 座標取得完了時のイベント・ハンドラ
void geocodingClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
  ……略……

  //結果のXMLをパースする
  XElement rootElement = XElement.Parse(e.Result);

  ……略……
}
価格取得処理内のWebClientクラス利用(上:Page.xaml.vb、下:Page.xaml.cs)

 WebClientクラスのインスタンスを作り、ダウンロード完了時に発生するイベントDownloadStringCompletedに対し、イベント・ハンドラを追加します。続いて、DownloadStringAsyncメソッドを呼び出し、Webサービスを呼び出します。“Async”なので、イベント・ハンドラは非同期で呼び出されることになります。

 Webサービス呼び出しが完了すると、DownloadStringCompletedイベントに追加したイベント・ハンドラがコールバックされます。コールバックされたイベント・ハンドラでは、DownloadStringCompletedEventArgs型の引数に、Webサービスを呼び出した結果が格納されてきます。具体的には、Geocoding APIを呼び出した結果の座標(緯度/経度)がXMLで格納されています。そのXMLをXElementクラスを使ってパース(解析)し、緯度/経度の値を取得します。

 さて、ここまでの流れを理解できると、次のガソリン価格情報WEBサービスapiを呼び出す処理は、説明するまでもないでしょう。取得した座標を利用して、新たにWebClientクラスのインスタンスを作り、Webサービスを呼び出すだけです。

 コード・ビハインド側コードのポイントの説明は以上です。異なるドメイン間の通信で制限があるなど、ASP.NETでのWebアプリとは違った特徴もありますが、簡単にWebサービスを利用できることが分かったのではないでしょうか。

まとめ

 それでは、まとめです。今回はWebサービスを利用したSilverlight 2アプリの開発方法について解説しました。

 今回のサンプルは、Geocoding APIとガソリン価格情報WEBサービスapiを利用して、住所から最寄りのガソリンスタンドを検索するアプリでした。サンプルの画面(XAML)側コードのポイントは、DataGridコントロールを利用した一覧の表示でした。また、その定義方法についても解説しました。そして、サンプルのコード・ビハインド側コードのポイントは、異なるドメイン間で通信する際の注意点、代理アクセスする方法、WebClientクラスの利用法でした。

 さて次回は、Silverlight 2でのファイル操作(アップロード)や、Isolated Storage(分離ストレージ)を利用したデータの永続化などのより基本となる機能について解説します。お楽しみに。では、さようなら。End of Article


 INDEX
  連載:続・無償環境でSilverlight 2アプリを開発しよう!
  第2回 Webサービスを利用するSilverlightアプリを作ろう
    1.サンプルを動かそう
    2.サンプルの概要と画面(XAML)側コードのポイント
  3.コード・ビハインド側コードのポイント

インデックス・ページヘ  「続・無償環境でSilverlight 2アプリを開発しよう!」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH