ダウンロードしたコンテンツの読み込み(3)
アプリケーションモジュールの読み込み
アプリケーションは、複数のモジュールに分割する方が管理しやすくなります。こうしたモジュールはクラスライブラリとして取りまとめ、アプリケーションの.xapファイルにパッケージ化することもあります。クラスライブラリを.xapファイルに追加すると、他の.NETプロジェクトと同様に参照できます。しかしその場合、.xapファイルのサイズが大きくなってしまい、ユーザーに無駄な待ち時間を強いることになりかねません。幸い、これをスマートに解決する方法があります。
Silverlightでは、モジュールをオンデマンドでダウンロードする柔軟なアプリケーションを作成できます。そのためには、まずはクラスライブラリを通常どおり作成します。しかし、Silverlightアプリケーションからそのライブラリを参照するのではなく、リモートサーバにアップロードしておき、WebClientクラスを使ってダウンロードする形にします。そして、ダウンロードしたライブラリはリフレクションにより利用します。コード9はその例です。
private void RequestContent()
{
Uri address =
new Uri("http://www.somedomain.com/MyClassLibrary.dll");
WebClient webClient = new WebClient();
webClient.OpenReadCompleted += new
OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(address); (1)
}
void webClient_OpenReadCompleted(object sender,
OpenReadCompletedEventArgs e)
{
AssemblyPart assemblyPart = new AssemblyPart(); (2)
Assembly assembly = assemblyPart.Load(e.Result); (3)
object myClass =
assembly.CreateInstance("MyClassLibrary.MyClass"); (4)
object result = myClass.GetType().InvokeMember( (4)
"GetCurrentTime", BindingFlags.InvokeMethod, null,
myClass, null); (4)
myTextBlock.Text = Convert.ToString(result); (4)
}
このコードは、アプリケーションモジュールを動的にダウンロードして使用する例です。アプリケーションモジュールはバイナリファイルの一種ですので、おなじみのOpenReadAsyncでダウンロードできます(1)。このメソッドが完了すると、ダウンロードしたStreamを使ってクラスライブラリにアクセスできます。しかし、クラスライブラリの中身を利用するためには、まずはAssemblyに変換する必要があります。
Assemblyはコンポーネントのメモリ内表現ですので、AssemblyPartクラスのインスタンスを通じてメモリに読み込むことができます(2)。このクラスは、アプリケーションのパッケージ(.xapファイル)に含めるアセンブリを表します。アセンブリを含めるには、ダウンロードしたStreamをAssemblyPartオブジェクトのLoadメソッドに渡します(3)。このメソッドにより、現在のアプリケーションドメインに新しいクラスライブラリが追加されます。
Assemblyをアプリケーションドメインに読み込んだら、その中身を利用できます。例えば、クラス、列挙型、構造体などです。さらに、こうした項目がメソッド、プロパティ、イベントなどのメンバを持つ場合、リフレクションを通じてこうしたメンバを呼び出すことができます。コードの(4)の部分がその例です。リフレクションは.NET Frameworkの基本機能であり、この記事では詳しく取り上げません。.NET Framework関連の書籍を見れば必ず説明があるはずです。ともあれ、オンデマンドでダウンロードしたクラスライブラリの中身を利用するためにはリフレクションを用いるということだけ頭に入れておいてください。さて、時として、ファイルをオンデマンドでダウンロードする処理がうまくいかないことがあります。例えば、要求が何らかの理由で中断された場合などです。次に、こうした状況への対処方法を見てみましょう。
要求処理の中断への対処
オンデマンドのダウンロード要求は、意図的に中断する場合と、予期せず中断する場合とがあります。意図的な中断は、ユーザーが非同期の要求をキャンセルした場合に発生します。キャンセルの処理方法については別のセクションで既に説明しました。また、不測の事態が発生してダウンロード要求がエラーになる場合もあります。いずれにせよ、ダウンロードしたコンテンツを利用する前に、ダウンロードが正常に完了したかどうかを確認する処理をきちんと組み込んでおくことが必要です。コード10はその例です。
void webClient_OpenReadCompleted(object sender,
OpenReadCompletedEventArgs e) (1)
{
if ((e.Cancelled == false) && (e.Error == null)) (2)
{
myTextBlock.Text = "Download Succeeded!";
}
}
このコードは、ダウンロードが成功したかどうかをチェックする方法の例です。このコードは、OpenReadAsyncメソッドで開始した要求に対して動作し、判別はOpenReadCompletedEventArgs型のパラメータで行います。また、DownloadStringAsyncメソッドで開始した要求の場合も、対処方法は同じです。DownloadStringCompletedEventArgsもOpenReadCompletedEventArgsも、同じAsyncCompletedEventArgsから派生しているからです。上記のコードで利用しているCancelledとErrorの2つは、いずれもこの派生元が公開しているプロパティです(2)。
Cancelledプロパティはbool型で、ダウンロード要求が中止されたかどうかを示します。中止の場合はtrue、それ以外の場合はfalseです。また、エラーが発生した場合には、Cancelledプロパティはfalseになります。その場合は、問題の詳細を示すExceptionがErrorプロパティに入っています。処理が成功だった場合には、コード10からも分かるように、Cancelledプロパティはfalseになり、Errorプロパティはnullになります。
まとめ
アプリケーションモジュールを必要に応じてダウンロードできるようにしておくと、最初の読み込みに必要な時間が短くなり、ユーザーの操作感が向上します。この強力な追加機能は、フォント、メディア、テキストの各コンテンツの取得などでも生かせます。また、複数の要素を取りまとめた圧縮ファイルをダウンロードすることもできます。いずれにせよ、実行時にコンテンツをオンデマンドでダウンロードできるのは、利用価値の高い機能です。
