はじめに
今回はネットワークアクセスを行うMap Appを作ってみましょう。Silverlightアプリケーションで画像やWebページダウンロードなどのWebアクセスは、
Webアクセス
NetworkManagerContract
ネットワークアクセスにはNetworkManagerContractを使用します。このContractで提供される機能を使用すると、
コードは、
[ImportSingle("Microsoft/NetworkManagerContract", ImportLoadPolicy.Synchronous)]
public NetworkManagerContract NetworkManagerContract { get; set; }
プラグインクラス
上記のプロパティの宣言を含む、
namespace NetworkSampleMapApp
{
using Microsoft.Maps.Core;
using Microsoft.Maps.Plugins;
using Microsoft.Maps.Network;
using Microsoft.Maps.MapControl;
using System;
using System.Xml;
using System.Windows.Controls;
public class NetworkSamplePlugin : Plugin
{
[ImportSingle("Microsoft/MapContract", ImportLoadPolicy.Synchronous)]
public MapContract DefaultMap { get; set; }
[ImportSingle("Microsoft/LayerManagerContract", ImportLoadPolicy.Synchronous)]
public LayerManagerContract LayerManagerContract { get; set; }
[ImportSingle("Microsoft/PushpinFactoryContract", ImportLoadPolicy.Synchronous)]
public PushpinFactoryContract PushpinFactoryContract { get; set; }
[ImportSingle("Microsoft/ModalDialogContract", ImportLoadPolicy.Synchronous)]
public ModalDialogContract ModalDialogContract { get; set; }
[ImportSingle("Microsoft/NetworkManagerContract", ImportLoadPolicy.Synchronous)]
public NetworkManagerContract NetworkManagerContract { get; set; }
private CityLayer mainLayer;
public override void Initialize()
{
base.Initialize();
this.mainLayer = new CityLayer(this.Token, this);
}
public override void Activate(System.Collections.Generic.IDictionary<string, string> activationParameters)
{
if (LayerManagerContract.ContainsLayer(this.mainLayer))
{
LayerManagerContract.BringToFront(this.mainLayer);
}
else
{
LayerManagerContract.AddLayer(this.mainLayer);
}
}
}
}
namespace NetworkSampleMapApp
{
using Microsoft.Maps.Core;
using Microsoft.Maps.Plugins;
using System;
public class CityLayer : Layer
{
private NetworkSamplePlugin plugin;
public CityLayer(PluginToken pluginToken, NetworkSamplePlugin plugin)
: base(pluginToken)
{
this.plugin = plugin;
this.Title = "Network sample";
}
}
}
以上のコードを元に、
PrioritizedWebClient
それでは、
var client = NetworkManagerContract.CreatePrioritizedWebClient();
Webページを文字列としてダウンロードするには、
client.Priority = NetworkPriority.Low;
client.DownloadStringCompleted += new EventHandler<PrioritizedDownloadStringCompletedEventArgs>(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri("http://gihyo.jp/"));
非同期メソッドのため、
void client_DownloadStringCompleted(object sender, PrioritizedDownloadStringCompletedEventArgs e)
{
if (e.Error != null)
{
ModalDialogContract.Open("Error", new TextBox() { Text = e.Error.ToString() });
}
else
{
ModalDialogContract.Open("Success", new TextBox() { Text = e.Result });
}
}
Webページダウンロード部分をメソッド化して、
private void DownloadString()
{
var client = NetworkManagerContract.CreatePrioritizedWebClient();
client.Priority = NetworkPriority.Low;
client.DownloadStringCompleted += new EventHandler<PrioritizedDownloadStringCompletedEventArgs>(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri("http://gihyo.jp/"));
}
void client_DownloadStringCompleted(object sender, PrioritizedDownloadStringCompletedEventArgs e)
{
if (e.Error != null)
{
ModalDialogContract.Open("Error", new TextBox() { Text = e.Error.ToString() });
}
else
{
ModalDialogContract.Open("Success", new TextBox() { Text = e.Result });
}
}
作成したDownloadStringメソッドを、
public override void Activate(System.Collections.Generic.IDictionary<string, string> activationParameters)
{
if (LayerManagerContract.ContainsLayer(this.mainLayer))
{
LayerManagerContract.BringToFront(this.mainLayer);
}
else
{
LayerManagerContract.AddLayer(this.mainLayer);
DownloadString(); // ← 追加
}
}
そして、
![図1 実行結果(エラー) 図1 実行結果(エラー)](/assets/images/dev/serial/01/bing-sdk/0005/thumb/TH800_001.png)
エラーが発生し例外の内容が表示されてしまったのではないかと思います。Silverlightアプリケーションでは、
異なるドメインへのアクセス
異なるドメイン間でSilverlightアプリケーションからWebサービスなどのコンテンツにアクセスできるようにするためには、
アクセス許可の方法は、
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
このclientaccesspolicy.
Silverlightアプリケーションは、
残念ながらRSSフィードやWeb APIなどを提供しているサーバーなどでも、
さて、
![図2 実行結果(成功) 図2 実行結果(成功)](/assets/images/dev/serial/01/bing-sdk/0005/thumb/TH800_002.png)
Adobe Flashでも同様の仕組みがあり
外部XMLファイルからプッシュピンの追加
第2回では、
![図3 県庁所在地 Bing Map App 図3 県庁所在地 Bing Map App](/assets/images/dev/serial/01/bing-sdk/0005/thumb/TH800_003.png)
今回紹介した方法で、
県庁所在地の情報サーバー
Webサーバー側に必要な作業は次の通りです。
- 独自ドメインのWebサーバーの用意
- clientaccesspolicy.
xmlファイルの配置 - 県庁所在地情報のXMLファイルの配置
サーバー側はドメインのルートにファイルを配置できる必要があります。そして、
県庁所在地の情報を書いたXMLファイルは以前と同じ内容のものです。下記のような情報を記述したファイルを、
<?xml version="1.0" encoding="utf-8" ?>
<Pushpins>
<Pushpin Name="札幌市" Latitude="43.0646147" Longitude="141.3468074" />
<Pushpin Name="青森市" Latitude="40.8243077" Longitude="140.7399984" />
<Pushpin Name="盛岡市" Latitude="39.7036194" Longitude="141.1526839" />
(省略)
<Pushpin Name="鹿児島市" Latitude="31.5610825" Longitude="130.5577279" />
<Pushpin Name="那覇市" Latitude="26.2124013" Longitude="127.6809317" />
</Pushpins>
以上でWebサーバー側の準備はできました。今回は静的なXMLファイルにアクセスしていますが、
プラグインの変更
プラグイン側を、
先ほどはPrioritizedWebClient クラスのDownloadStringAsyncメソッドを使用して文字列としてダウンロードしていました。これでも問題ありませんが、
private void OpenRead()
{
var client = NetworkManagerContract.CreatePrioritizedWebClient();
client.OpenReadCompleted += new EventHandler<PrioritizedOpenReadCompletedEventArgs>(client_OpenReadCompleted);
client.OpenReadAsync(new Uri("http://katamari.jp/Cities.xml")); // Web サーバー上の XML ファイルを指定
}
特に難しいところはありませんね。実際にストリームを処理するメソッドは次のようになります。
void client_OpenReadCompleted(object sender, PrioritizedOpenReadCompletedEventArgs e)
{
if (e.Error != null)
{
return;
}
using (var reader = XmlReader.Create(e.Result, new XmlReaderSettings()))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element &&
reader.LocalName == "Pushpin")
{
// Entity の作成
var entity = new Entity();
// 県庁所在地名
reader.MoveToAttribute("Name");
var name = reader.Value;
// 経緯度
var location = new Location();
reader.MoveToAttribute("Latitude");
location.Latitude = double.Parse(reader.Value);
reader.MoveToAttribute("Longitude");
location.Longitude = double.Parse(reader.Value);
// プッシュピンの追加
entity.Primitive = this.PushpinFactoryContract.CreateStandardPushpin(location, name[0].ToString());
// レイヤーに追加
this.mainLayer.Entities.Add(entity);
}
}
}
}
最後に作成したOpenReadメソッドを呼ぶようにActivateメソッド部分を書きかえて、
![図4 県庁所在地の表示 図4 県庁所在地の表示](/assets/images/dev/serial/01/bing-sdk/0005/thumb/TH800_004.png)
おわりに
今回はMap AppからWebアクセスについて紹介しました。実際にMap Appを作成する場合、