データ ポイント

Silverlight 3 でアウト オブ ブラウザ クライアントを構築する

John Papa

この記事は、プレリリース版の Silverlight 3 および Expression Blend に基づいています。

コードは MSDN コード ギャラリーからダウンロードできます。
オンラインでのコードの参照

目次

目標
デスクトップへのインストール
マニフェストの設定
オフライン実行
ネットワーク接続
データのオフライン保存

Silverlight 3 アプリケーションの実行環境は、もはやブラウザに限定されません。ブラウザ内だけでなく、ブラウザからデタッチし、デスクトップから実行できるようになりました。このようなアプリケーションを "アウト オブ ブラウザ アプリケーション" と呼びます。ブラウザ内でしか実行できないという従来の制限を打ち破り、Silverlight 3 アプリケーションの豊富な機能を直接デスクトップにもたらします。

今月のコラムのテーマは、データ ドリブン型のスタンドアロン Silverlight 3 アプリケーションの構築です。最初に、サンプル アプリケーションの概要を簡単に紹介します。次に、アプリケーションをブラウザから切り離し、動作させるために必要な手順を大まかに解説します。ブラウザから切り離すには、接続の検出など、別途いくつかの機能が必要になります。ここでは、オフライン アプリケーションのステータスを検出する方法や、ネットワーク接続が中断された場合にデータをオフラインで保存する方法を中心に、アウト オブ ブラウザ アプリケーションへのアイコンの組み込み、クライアント コンピュータに対する分離ストレージを使用したデータの保存、アウト オブ ブラウザ アプリケーションのステータス表示、状態変化イベントの処理などの機能についても随時、解説していきます。サンプル アプリケーションは、Twitter ライクなクライアントの簡易版です。サーバーとの間でメッセージを送受信します。すべてのサンプルは、今月のコード ダウンロードに収録されています。

目標

アウト オブ ブラウザの機能を実際に掘り下げて解説するよりも、実際、どのような機能を使って、サンプル アプリケーションを構築するのか、あらかじめ知っていただいた方がよいので、まずは、その趣旨を大まかに説明することにしましょう。サンプル アプリケーションは、Silverlight 3 とそのアウト オブ ブラウザ機能を使用して、データ ドリブンなアプリケーションを構築する方法を紹介するものです。サンプル アプリケーションの最終的な目標は、Twitter クライアントの作成です。新規メッセージを送信したり、友人のタイムラインや返信、ダイレクト メッセージを取得したりできることが条件となります。シンプルな簡易版の Twitter クライアントですが、ここで取り上げるモデルに従って、さまざまな機能を追加することもできます。図 1 は、ブラウザの外で実行されているサンプル アプリケーションです。

fig01.gif

図 1 Silverlight Twitter クライアント

SilverTwit アプリケーションの [Home] ボタンをクリックすると、自分がフォローしているすべてのユーザーのメッセージが要求されて、表示されます。[Replies] ボタンをクリックすると、ログイン ユーザーへの返信が取得されて表示されます。同様に、[Direct] ボタンをクリックすると、ログイン ユーザーへのダイレクト メッセージが取得されて表示されます。メッセージ要求は、Silverlight のアウト オブ ブラウザ アプリケーションから Web サービス (サンプル プロジェクトに付属) へと送信され、Web サービスが、その要求をパブリック Twitter API へと中継します。Web クライアントから Twitter への直接クロスドメイン通信は許可されていないため、このように、サードパーティのサービスを介して中継する必要があります。ただし、サンプル ソリューションで使用されているようなサーバー アプリケーションからの呼び出しは許可されています。それ以外にも、PopFly や Yahoo Pipes などを使用して、要求を中継する方法があります。

クロスドメイン ポリシーの詳細については、2008 年 9 月号の私の「データ ポイント」コラムを参照してください。このコラムでは、ファイル形式とポリシーの機能について説明しています。

ユーザーがメッセージを入力し、[Post] ボタンをクリックすると、そのメッセージが中継 Web サービスを介して Twitter に送信されます。ネットワーク接続を検出できない場合、その間に投稿されたメッセージは、ネットワーク接続が復元されるまでの間、ローカルに保存されます。保留されていたメッセージは、接続が復元した時点で、Twitter に送信されます。

図 1 のサンプル アプリケーションのウィンドウ枠に注目してください。アプリケーション アイコンやアプリケーション タイトルのほか、各種の標準アイコン (最小化、最大化、閉じる) が表示されています。Visual Studio または Expression Blend でアプリケーションを作成している場合、ウィンドウやデスクトップなどで使用されるアプリケーションのタイトルとアイコンはカスタマイズできます。このウィンドウは sllauncher.exe プロセスによって起動され、このプロセスが Silverlight 3 アウト オブ ブラウザ アプリケーションをホストします。

SilverTwit サンプル アプリケーションの一番下の領域には、ネットワーク接続が検出されたかどうか、アプリケーションがブラウザ内で実行されているかブラウザ外で実行されているか、アプリケーションがデタッチされたかどうかなどの統計情報が表示されます。アウト オブ ブラウザ アプリケーションの動作は、こうした機能を利用して決定されます。たとえば、ネットワーク接続が検出されなければ、新しいメッセージを探したり、新しいメッセージを Twitter に送信したりする必要はありません。このようにネットワーク接続が切断された状態の場合、アプリケーションは、それに応じた対応が求められます。アプリケーションの下の方には、[Detach] ボタンも存在します。このボタンをクリックすると、アプリケーションがデタッチされてブラウザの外で実行されます。

デスクトップへのインストール

Silverlight 2 アプリケーションの実行環境は、ブラウザ内に限定されます。これに対し、Silverlight 3 アプリケーションは、ブラウザ内でも、ブラウザの外でも実行できます。アプリケーションをブラウザの外に切り離すプロセスを "デタッチ" といいます。デタッチされた Silverlight 3 アプリケーションは、[スタート] メニューやデスクトップ アイコンから実行することができます。デスクトップ上で動作するアウト オブ ブラウザ アプリケーションは、sllauncher.exe プロセスがホストしているウィンドウ内で実行されます。アウト オブ ブラウザ アプリケーションは、デタッチされている間も、ネットワークにアクセスすることができます。また、Silverlight から利用できるものであれば、.NET Framework のすべてのライブラリを使用することが可能です。ただし、アウト オブ ブラウザ アプリケーションには、いくつかの制限があります。たとえば、ブラウザ内でホストされる Silverlight アプリケーションとは異なり、アウト オブ ブラウザ アプリケーションのホストはブラウザではありません。したがって、ブラウザの DOM と通信することはできません。

図 2 は、Silverlight 3 アプリケーションをまずブラウザ内で実行してから、デタッチする方法を大まかに示したものです。[Detach] ボタンをクリックすると、まず、図 2 のイベント ハンドラが実行され、最終的に Application.Current Detach() メソッドが実行されます。このアーキテクチャを図 3 に示します。Application.Current.Detach メソッドはデタッチに失敗すると例外を生成するため、何かエラー処理があった方がよいと思います。

図 2 ブラウザからのデタッチ

private void DetachButton_Click(object sender, RoutedEventArgs e)
{
    try {
        Application.Current.Detach(); // take the app out of browser
    }
    catch (InvalidOperationException opex)    {
        MessageBox.Show("Application is already detached" +
          " to the desktop.");
    }
    catch (Exception ex)    {
        MessageBox.Show("Application could not be detached" +
          " to the desktop."+ Environment.NewLine + 
          ex.Message);
    }
}

fig03.gif

図 3 Silverlight アプリケーションをデタッチしてブラウザの外で実行

さらに、ブラウザからアプリケーションをデタッチしてよいか確認を求めることををお勧めします。デスクトップや [スタート] メニューに、アウト オブ ブラウザ アプリケーションのショートカットを追加するオプションを追加することも考えられます。ユーザーが [OK] をクリックすると、アプリケーションがデスクトップにインストールされ、(sllauncher.exe プロセスによってホストされる) 起動処理が開始されます。この時点で、ブラウザは終了できます。アウト オブ ブラウザ アプリケーションは引き続き、それ自身で実行されます。

アプリケーションを削除するには、アウト オブ ブラウザ アプリケーション上で右クリックし、ポップアップ メニューの [Remove Application] をクリックします。この操作は、アプリケーションをブラウザ外で実行しているときに行えるほか、同じバージョンをブラウザ内で実行しているときに行うこともできます。アプリケーションを削除すると、デスクトップからも [スタート] メニューからも、アイコンが削除されます。アウト オブ ブラウザ アプリケーションは、コントロール パネルの [プログラムの追加と削除] には表示されません。

マニフェストの設定

アプリケーションをオフラインにするのは簡単です。開発の観点から見ても、ほぼ同じことが言えます。Silverlight 3 Beta でアプリケーションをブラウザから切り離して実行するには、Silverlight プロジェクトで、appmanifest.xml ファイルに、いくつかの簡単な変更を加えるだけです。この変更を行わないと、Silverlight アプリケーションをデタッチし、ブラウザの外で実行することはできません。AppManifest.xml の既定の格納場所は Properties フォルダです。このファイルを直接編集して、アウト オブ ブラウザの機能を追加することができます。

図 4 は、サンプル アプリケーションの AppManifest.xml ファイルです。新しい Deployment.ApplicationIdentity セクションで注目していただきたい部分を太字で示しました。ShortName は、アウト オブ ブラウザ アプリケーションのショートカットに使用されます ([スタート] メニューとデスクトップのショートカット)。Title は、アウト オブ ブラウザ アプリケーションのタイトル バーに表示されます。Icons は省略可能です。ただし、すべてのアイコンを含めるか、一切含めないかのどちらかにする必要があります。最終的にリリースされる Silverlight 3 では、この要件が変更される可能性がありますが、ベータ版に関しては、全部のアイコンを指定しないと、アウト オブ ブラウザが正しく動作しません。[スタート] メニューのショートカット、デスクトップ アイコン ショートカット、アウト オブ ブラウザ アプリケーションのウィンドウ アイコン、アプリケーションをブラウザの外にインストールするかどうかを確認するプロンプトのダイアログなど、状況に応じてさまざまなアイコンが使用されます。

図 4 AppManifest.xml の設定

<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        EntryPointAssembly="SilverTwit"    
        EntryPointType="SilverTwit.App">   
  <Deployment.Parts>
    </Deployment.Parts>
  <Deployment.ApplicationIdentity>
    <ApplicationIdentity
         ShortName="SilverTwit"
         Title="SilverTwit - Silverlight Twitter Client">
      <ApplicationIdentity.Blurb>Tweet, tweet and retweet</ApplicationIdentity.Blurb>
      <ApplicationIdentity.Icons>
        <Icon Size="16x16">images/SilverTwit16.png</Icon>
        <Icon Size="32x32">images/SilverTwit32.png</Icon>
        <Icon Size="48x48">images/SilverTwit48.png</Icon>
        <Icon Size="128x128">images/SilverTwit128.png</Icon>
      </ApplicationIdentity.Icons>
    </ApplicationIdentity>
  </Deployment.ApplicationIdentity>
</Deployment>

オフライン実行

Silverlight 3 に追加された新機能としては、もう 1 つ、Application.Current.RunningOffline プロパティがあります。Silverlight アプリケーションがオンライン (ブラウザ内) で実行されているか、オフライン (ブラウザ外) で実行されているかを Boolean 値で返すプロパティです。特に、ブラウザの DOM と通信するコードを Silverlight から実行する場合、オフラインかオンラインかが重要な意味を持ちます。オンラインで実行している場合、アプリケーションは、ブラウザの DOM と通信できます。しかし、オフラインで実行している場合、アプリケーションは、ブラウザではなく sllauncher.exe プロセスでホストされるため、DOM は存在しません。したがって、このコードを実行する場合は、あらかじめ、RunningOffline プロパティをチェックする必要があります。

アウト オブ ブラウザ アプリケーションの初回実行時は、常に既定のサイズで開きます。一度開いた後は、サイズ変更、最大化、最小化、閉じるなど、ウィンドウを適宜操作できます。現在、Silverlight 3 Beta では、ウィンドウそのものの起動時のサイズやコントロールを変更することはできません。

図 1 に示したサンプル アプリケーションは、ブラウザの外で実行されています。このことは、ウィンドウの下の方に表示される "Running Out of Browser (ブラウザの外で実行中)" というメッセージで確認できます。このチェックには、図 5 のコードが使用されています。アプリケーションがブラウザ内で実行されている場合、このメッセージは "Running In Browser (ブラウザ内で実行中)" になります。図 6 を見てください。アプリケーションをブラウザ内で実行したようすです。

図 5 オンラインかオフラインか

private void SetOfflineStatus()
{
    if (Application.Current.RunningOffline)
        stats.RunningModeMessage = "Running Out of Browser";
    else
        stats.RunningModeMessage = "Running In Browser";
}

fig04.gif

図 6 オンラインで実行中

アプリケーションの実行状態が変化した場合に、ExecutionStateChanged というイベントで通知を受けることができるようになりました。これも Silverlight 3 の新機能です。イベントの発生に関係する 5 つの状態が、ExecutionStates 列挙子として存在します。

  • RunningOnline: ブラウザ内で実行中
  • Detaching: アプリケーションをブラウザからデタッチ中
  • Detached: ブラウザからデタッチされブラウザ外で実行中
  • DetachedUpdatesAvailable: "Detached" と同じ (ただし、更新版が利用可能)
  • DetachedFailed: デタッチ イベントでエラーが発生

図 1 (オフライン実行) と図 6 (オンライン実行) で、アプリケーションの下の方の領域を見てください。既にアプリケーションがデタッチされているため、現在の状態が "Detached" と表示されています。イベントに変化が生じると、アプリケーション内のメッセージがデータ バインドを使って自動的に更新されます。

Silverlight のデータ バインドの詳細については、2008 年 9 月号の私の「データ ポイント」コラム「Silverlight 2 と WCF を使用したサービス駆動型アプリケーション」を参照してください。このコラムの中で、データ バインドやバインド モードについて解説しています。

以上の状態をリッスンするイベント ハンドラを設定するには、次のように、ExecutionStateChanged イベントを処理します。

Application.Current.ExecutionStateChanged += new EventHandler(Network_ExecutionStateChanged);

DetachUpdatesAvailable の状態で ExecutionStateChanged イベントが発生した場合、Silverlight 3 のアウト オブ ブラウザ アプリケーションが、新しいバージョンの Silverlight 3 アプリケーションを検出した、つまり、更新版をダウンロードできる、ということになります。そこで、ユーザーはアウト オブ ブラウザ アプリケーションをいったん終了し、開き直すと、自動的に更新版を受信できます。図 7 を見てください。これは、ExecutionStateChanged イベントが発生したときに、アウト オブ ブラウザ アプリケーションに表示されるメッセージです。

fig05.gif

図 7 更新版がダウンロード可能

ネットワーク接続

Silverlight 3 の新機能をもう 1 つ紹介します。System.Net 名前空間の NetworkInterface.GetIsNetworkAvailable() メソッドにより、ネットワーク接続が使用可能かどうかを検出できるようになりました。Web サービスとの通信を伴うアウト オブ ブラウザ アプリケーションを実行する場合、このチェックは不可欠です。ネットワーク接続がダウンしている場合、アプリケーションで何らかの回避策を実行できます。たとえば、ユーザーに問題の発生を通知したり、ネットワーク接続が復旧するまでの間、データをローカルに保存しておくなどの回避策が考えられます。

NetworkChange.NetworkAddressChanged イベント (System.Net.NetworkInformation クラスにも存在) は、ネットワーク アドレスの変更が検出された場合に発生します。このイベントは、次のように処理できます。

NetworkChange.NetworkAddressChanged += 
  new NetworkAddressChangedEventHandler(NetworkChange_  NetworkAddressChanged);

図 8 のコードは、NetworkAddressChange イベントのイベント ハンドラです。このコードでは、まず、ブール型のステータス プロパティ IsNetworkAvailable を設定しています。このプロパティが Silverlight の UI にバインドされ、ユーザーにネットワーク接続のステータスを通知します。図 9 は、アウト オブ ブラウザ アプリケーションがネットワーク アドレスの切断を検出したところです。バインドによって、メッセージが更新され、ステータスが赤色で表示されています。この動作をテストする簡単な方法があります。ネットワーク接続ダイアログを開いて、すべてのネットワーク接続を無効にすることです。そうすると、NetworkAddressChanged イベントが発生し、データ バインドを通じて UI が更新されます。

図 8 ネットワーク アドレスの変化を検出

private void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
{
    stats.IsNetworkAvailable = NetworkInterface.GetIsNetworkAvailable();

    if  (NetworkInterface.GetIsNetworkAvailable())
    {
        // get the stored tweet, try to post it
        if (IsolatedStorageSettings.ApplicationSettings.Contains(TWEET_STORAGE))
        {
            PostTweet(IsolatedStorageSettings.ApplicationSettings[TWEET_STORAGE].ToString());
        }
    }
}

fig09.gif

図 9 ネットワーク アドレスが利用不可

アプリケーションの実行中にネットワーク接続が失われたとしても、Twitter にメッセージを投稿できた方が親切です。ネットワーク接続がアクティブであったも、Twitter サービスがダウンしている可能性もあります。Twitter が実行されているかどうかは、サービスに対して ping を実行するなどして確認できます。サンプル アプリケーションは、ネットワーク接続が利用できなくても、メッセージを投稿できるようになっています。ただし、すぐには Twitter に送信できないので、メッセージは、いったん分離ストレージ (Silverlight のローカル永続化ストア) に保存されます。図 8 を見るとわかるように、ネットワークの変化が検出されたとき、ネットワークが利用可能で、なおかつ、分離ストレージにメッセージが存在すると、メッセージが Twitter に投稿されます。

Silverlight の分離ストレージの詳細については、2009 年 2 月号の私の「データ ポイント」コラム「Silverlight のシンジケート データと分離ストレージ」を参照してください。

データのオフライン保存

アプリケーションがネットワーク アドレスを検出できないときに、ユーザーがメッセージの投稿を試みた場合、そのデータは分離ストレージに保存されます。サンプル アプリケーションでは、一度に保存できるメッセージは 1 つだけですが、各メッセージを別々に保存するか、XML にまとめるなどして、保存できるメッセージを増やすこともできます。図 10 は、ネットワークが利用可能かどうかをチェックするコードです。利用可能な場合は、メッセージが Twitter に送信されます。ネットワークが利用できない場合、分離ストレージに既存のメッセージが存在するかどうかを確認します。既存のメッセージが存在した場合、一度に保存できるメッセージは 1 つだけであるという内容のメッセージを表示します

図 10 Twitter にメッセージを送信

private void PostTweet()
{
    string tweetText = TweetTextBox.Text;
    if (!NetworkInterface.GetIsNetworkAvailable())
    {
        if (IsolatedStorageSettings.ApplicationSettings.Contains(TWEET_STORAGE))
        {
            MessageBox.Show(
                "Network connection is not available and only 1 tweet" + 
                " can be stored for delayed posting to Twitter.");
        }
        else
        {
            IsolatedStorageSettings.ApplicationSettings.Add(TWEET_STORAGE, tweetText);
            MessageBox.Show(
                "Network connection is not available. The post" +
                " will be stored until connectivity returns.");
        }
        return;
    }

    PostTweet(tweetText);
}

アウト オブ ブラウザ アプリケーションには、自動的に 25 MB の記憶域が分離ストレージに確保されます。ブラウザでホストされたオンラインの Silverlight アプリケーションの場合の容量は 1 MB です。それ以上の記憶域が必要な場合は、IsolatedStorageFile.IncreaseQuoteTo という API を使用して要求できます。この場合、容量を増加してよいかどうか確認するプロンプトが表示され、ユーザーが許可するか拒否するかを決めることができます。

分離ストレージにメッセージが存在しない場合、ユーザーによって投稿された新しいメッセージが保存され、ネットワーク接続が再度確立された時点で送信されます。ネットワーク アドレスが再度確立されると、NetworkAddressChanged イベント ハンドラが作動し、分離ストレージからメッセージを取り出して送信します (図 8 を参照)。

ご覧のように、Silverlight 3 のアウト オブ ブラウザ ソリューションによって、Silverlight アプリケーションは、ブラウザやネットワーク接続が利用できなくても、デスクトップ上で実行できるようになりました。必要に応じて、ネットワーク接続を検出したり、ネットワーク イベントの発生時に何らかのアクションを実行したり、データをローカルに保存したりするしくみも利用できるようになっています。ぜひ試してみてください。工夫しだいですばらしい用途が実現することでしょう。

ご質問やご意見は、John (mmdata@microsoft.com) まで英語でお送りください。

John Papa (johnpapa.net) は、ASPSOFT の上級コンサルタントです。野球ファンで、夏の夜を家族と共にヤンキースの応援に費やします。C# の MVP、Silverlight の事情通、そして INETA の講演者でもある John は、何冊かの書籍を発表しており、最新の著書は『Data-Driven Services with Silverlight 2』(O'Reilly、2009 年) です。また、主にカンファレンス (Mix、DevConnections、VSLive など) での講演で活躍しています。