はじめに
Silverlightと言うとリッチなユーザーインターフェイスや、アニメーションと言ったインタラクティブな要素ばかり注目されがちですが、Silverlight 2(以下 Silverlight)からは、ジェネリックやLINQ、スレッドといった.NET Frameworkの機能がサポートされました。これによりSilverlightでは.NET Frameworkのライブラリを使用し、効率的に業務アプリケーションを構築できるようになったという点も忘れてはいけません。
今回はSilverlightで使用できる.NET Frameworkの最新技術とSilverlightの連携について触れていきたいと思います。
対象読者
Silverlight開発初心者。
Silverlight概要の復習
最初にSilverlightの概要について振り返っておきましょう。Silverlightは本連載の1回目でも触れたように、図1のアーキテクチャで構成されています。
Silverlightは.NET Framework 3.5のサブセットとして実装されています。つまり、コレクションの検索や、サーバー側アプリケーションとの連携、.NET Frameworkと同じ型システム、ガーベッジコレクタといった.NET Frameworkの共通基盤をSilverlightでも利用できるようになったということです。
また、分離ストレージを使ったユーザー情報の保存、スレッドを使った非同期プログラミング、HTML DOMとの連携といったインターネットアプリケーションの構築を助けるためにの機能が豊富に提供されているのもSilverlightの特徴の一つです。
Silverlightが提供している機能の概要を表1に示します。
機能 | 説明 |
データ操作 | LINQによる、多種多様なデータソースへのアクセスを行う機能を提供 |
基本クラスライブラリ | 文字列処理、コレクション、国際化、などのクラスライブラリを提供 |
WCF(Windows Communication Foundation)との連携 | リモートサービスにアクセスするため、各種データ通信プロトコルをサポート |
DLR(動的言語ランタイム) | Silverlight上で、JScriptやRuby、Pythonといった動的言語の動作をサポート |
分離ストレージ | ユーザー個別の情報をユーザーのローカルコンピュータ内に保存する機能を提供 |
非同期プログラミング | BackgroundWorkerクラスを提供し、簡単なスレッドプログラミングをサポート |
HTML DOMとの連携 | HTML DOMとSilverlightの相互運用をサポート |
シリアル化 | JSONおよびXMLのCLRオブジェクトへのシリアル化をサポート |
複数プログラミング言語のサポート
今までクライアントサイドのプログラミングと言えば、HTMLであればJavaScript、FlashであればActionScriptを使ってプログラミングを行っていました。この2つの言語は習得にそれほど時間がかかるわけではありませんが、普段プログラミングを行っているC#やVisual Basicなどとは違った動的に型付けされた言語であり、静的に型付けされた言語とは違うプログラミングが必要とされました。
プログラミングのバグの中で最も発見が困難な類のバグは、型に基づいたバグだと筆者は考えています。例えば最初は整数型で宣言していた変数がプログラム中のコードにより、いつの間にか文字列型の変数に置き換わっていたため、計算結果がおかしくなってしまったり、本来はインスタンスが持っていないはずのメソッドを呼び出すコードを記述し、実行時に初めてエラーに気付くといった問題です。
var total = 0; // total の値は 0 (int) total = total + "1"; // total の値は 01 (string) var s = "abc"; s.method1(); // 実装していないメソッドの呼び出し
静的言語では、これらのバグはコンパイル時にチェックし、インスタンス同士の型変換が可能であるか、インスタンスは指定されたメソッドを持っているかなどをコンパイル時に発見することが可能になっています。特に業務アプリケーションのように大人数で作成するアプリケーションではプログラマーの力量もバラバラなことが多く、コンパイル時にチェックできるものはできるだけコンパイラーによって検知できる仕組みがある言語が望まれていました。
しかし、動的言語が業務アプリケーション開発に向いていないと言っているわけではありません。確かに静的な型チェックがないためコーディングの際に注意が必要ですが、本来プログラムは目的を記述するためのものであり、型情報はある意味ノイズであると考えることもできます。動的言語では型を動的に決定することでコーディング量を少なくし、簡潔にプログラミングすることが可能になります。
Silverlightでは後述するDLRを使うことで、CLR上で動作する動的言語の基盤もサポートしています。現在のところSilverlightでは、JScriptやIronRuby、IronPythonといった言語がサポートされています。
Silverlightの基本機能
今回は、図1中の上部にある.NET Framework for Silverlightの部分を掘り下げて、Silverlightがどのように業務アプリケーションで利用できるかを解説していきます。
Silverlightと.NET Framework
Silverlightでは図1や表1で紹介したように、.NET Framework 2.0で登場したジェネリックや.NET Framework 3.5で登場したLINQといった.NET Frameworkの最新技術を使用してプログラミングを行うことができます。ここでは簡単に、業務アプリケーションで使用する上で役に立ちそうなSilverlightの基本機能について紹介します。
ジェネリック
「ジェネリック」は.NET Framework 2.0で導入された機能で総称型とも呼ばれます。
ジェネリックでは、型付けされたコレクションを簡単に利用できます。型付けされたコレクションを使うことで、予期しない型のインスタンスがコレクションを追加することができなくなるため、プログラムの堅牢性が向上し、不要なキャストが必要なくなるためコレクションの操作も高速になります。
リスト2では、wingsUsersというWingsUser型のコレクションを作成し要素を追加していますが、偽WingsUserはstring型のインスタンスであるため、コレクションに追加することはできません。
var wingsUsers = new List<WingsUser>{ new WingsUser { Name = "山田" }, new WingsUser { Name = "かるあ" }, }; wingsUsers.Add("偽WingsUser"); // コンパイルエラー
wingsUserがどんな型のインスタンスでも受け入れるコレクションだったらどうなるでしょう。プログラムコードでは、要素の一つ一つに対し、それが想定している型のインスタンスかをチェックし、キャストしてからアクセスする必要があります。ジェネリックを使うことで想定していない動作防ぐことができプログラムの堅牢性が向上します。
スレッド
ボタンがクリックされた際に、時間がかかる処理を行っているため、UIが操作を受け付けず固まったようなアプリケーションを見たことはありませんか? これはUIスレッドで時間のかかる処理を行っているため、UI側に処理が返却されないことが原因で起こる問題です。JavaScriptの場合、リスト3のようにsetTimeout
関数を使って疑似的にスレッドを表現します。
function button1_Click() { setTimeout(重い処理, 1); } function 重い処理() { // 重い処理 }
setTimeout
関数は指定時間後に定義した処理を実行する関数です。この場合、1ミリ秒後に重い処理()
を実行しますが、UIスレッド自体はbutton1_Click
メソッドを終了してUIに処理を戻しているため、重い処理()
が別スレッドで動作しているように見えます。
Silverlightでは.NET Frameworkのスレッドをサポートしているため、リスト4のようにBackgroundWorkerなどのクラスを使うことで簡単にスレッドに対応したアプリケーションを作成することができます。
private void Button_Click(object sender, RoutedEventArgs e) { var 重い処理を行うスレッド = new BackgroundWorker(); 重い処理を行うスレッド.DoWork += 重い処理; 重い処理を行うスレッド.RunWorkerAsync(); } private void 重い処理(object sender, DoWorkEventArgs e) { // 重い処理 }
スレッドによるプログラミングではUI要素へのアクセスで注意が必要です。WindowsFormではUIスレッド以外のスレッドからUIの要素にアクセスすることは禁止されていました。Silverlightも同様に、UIスレッド以外からUIの要素にアクセスすると、UnauthorizedAccessException例外が発生します。
WindowsFormアプリケーションでは、各コントロールに用意されているInvoke
メソッドを使って非同期に各コントロールにアクセスしますが、SilverlightではコントロールはInvoke
メソッドをサポートしていません。SilverlightでUIスレッド以外からUI要素にアクセスするためには、リスト5のようにScriptObjectが公開するDispatcher
プロパティのBeginInvoke
メソッドを使用してUI要素へアクセスします。
private void 重い処理(object sender, DoWorkEventArgs e) { // 重い処理 // UI への書き込み Dispatcher.BeginInvoke(delegate() { result.Text = "重い処理終了"; }); }
LINQ
LINQ(Language INtegrated Query)は.NET Framework 3.5で導入された機能で言語統合クエリとも呼ばれています。LINQでは、オブジェクトやXMLといったコレクションに対して検索や更新、オブジェクトの付け替えを簡単に行える機能が提供されています。
Silverlightはクライアント側の技術であるため、データベースに格納されたデータの表示、更新といった作業はサーバー側プログラムとの連携を行って実現する必要があります。このため、クライアント側にダウンロードしたデータの表示内容をカスタマイズしたり、キャッシュしたデータに対し再検索するといった機能が重要になります。
LINQを使用することで、ダウンロードしたオブジェクトに対する検索や、データの表示内容の変更といった作業をシンプルにコーディングすることができるようになります。
例えばリスト6では、GetUsers
メソッドがサーバーからユーザーの一覧を取得するメソッドだったとして、その後のコードで、習得したデータに対して再検索を行っています。
var serviceResult = GetUsers(); // 検索結果の再検索、並び替え var query1 = from user in serviceResult where user.Name.StartsWith("か") orderby user.Name ascending select user;
データグリッドを使った検索画面や、更新処理などのリストデータを扱うシナリオを考えた場合、サーバーとの通信で取得したデータに対し、検索や更新を行うことでパフォーマンスの向上を図ることができます。
実際のサーバーサイドアプリケーションとの連携に関しては次回以降の連載で詳しく解説します。
JSON形式のデータをサポート
JSON(JavaScript Object Notation)はJavaScriptにおけるデータの表現方法の一つです。例えば先ほど例に挙げたWingsUserの一覧をJSONではリスト7のように表すことができます。
var members = [ { name; '山田'}, { name: 'かるあ' }, ];
JSONでは、配列を[]で、オブジェクトを{}でそれぞれ定義します。
この場合、members変数にはnameというプロパティを持つオブジェクトの配列が格納されます。このようにJSONを使うことでシンプルな構文でデータ表現が行えるため、この頃ではXMLの代わりにJSONによるデータ表現を使ったWebServiceも増えています。
SilverlightではJSON形式のデータをCLR型にマッピングすることが可能です。
リスト8では、JSON形式で宣言されたオブジェクトをデシリアライズしてWingsUsreの配列にマッピングしています。
List<WingsUser> GetUser() { var textReader = new System.IO.StringReader( "[ { name: 'かるあ' }, { name : 'やまだ' } ]" ); var jsonData = (JsonArray)JsonArray.Load(textReader); var query = from member in jsonData select new WingsUser { Name = member["name"] }; return query.ToList(); }
JsonArray.Load
メソッドは、引数に渡されたストリームからJSON形式のデータをロードし、CLRの型にマッピングします。以降のプログラムではロードされたデータに対し、ディクショナリからデータを取り出してプログラミングを行います。
Load
メソッドで取得したデータに対しては、"name"などの文字列を使ってデータにアクセスする必要があるため、キーの指定間違いなどで実行時エラーが発生する可能性があります。JSONを使ったプログラミングでは、直接JsonArray型やJsonObject型に対してプログラミングをするのではなく、リスト8のように一度.NETのクラスにマッピングしてからデータにアクセスすることで、実行時エラーの範囲を小さくすることができます。
SilverlightとDLR(Dynamic Language Runtime)
SilverlightではDLR上でPythonやRuby、JScriptといった言語での開発をサポートしています。本項では、SilverlightにおけるDLRが業務アプリケーションにどのように役立つのかを調べていきたいと思います。
DLRとは
DLR(Dynamic Language Runtime)とは、.NET Frameworkで動的言語を動作させるための実行基盤です。DLRによって、各動的言語間の型を一貫して提供することで、動的言語間やC#やVisual Basicと言ったCLR(Common Language Runtime)の言語間の会話を可能とします。現在サポートされている動的言語はIronPython、IronRuby、Managed JScriptの3つですが、DLRの登場で.NET Framework上で動的言語を作りやすくする環境が整備されたということになります。
SilverlightとDLRの関係
DLRは図2のように、.NET Frameworkや.NET Framework for Silverlightの上に実装され、コンソールアプリケーションやASP.NET、Silverlightといった環境にホストされます。
つまり、DLR上に構築された動的言語を使用すれば、コンソールアプリケーション、ASP.NET、Silverlightといったアプリケーションで動的言語を使用したり、C#やVisual Basicといった言語から、動的言語で実装された機能を呼び出すことが可能になるのです。
また、Silverlightでは、後述するHTML DOMとの統合機能によってSilverlightからクライアントのHTMLを操作することが可能なため、JavaScriptの代わりに動的言語を使用してHTMLの操作を行うことも可能になっています。
SilverlightでDLR対応言語を使用するためには
SilverlightでDLRを使用するためには、CodePlexで提供されているSilverlight Dynamic Languages SDKを使ってプログラミングを行う必要があります。
このSDKには、SilverlightでIronPythonやIronRuby、JScriptといった言語を動作させるためのdllと、各言語でSilverlightアプリケーションを作成するためのテンプレート、xapファイルの作成コマンドといった物が含まれます。
使い方については、同梱されているReadme.txtを確認してください。
動的言語を使うメリット
.NET Framework上で動的言語を使用できるとして、業務アプリケーションを開発する際のメリットはどのような物があるでしょうか。
筆者は動的言語を使うことで次のようなメリットがあると考えています。
- 動的言語の開発経験をそのままSilverlightで使用することが可能
- 動的言語を「のりしろ」的な役割で使用することで柔軟な対応が可能
1つ目の利点については説明は不要でしょう。DLRでは、現在正式にサポートされているIronRubyやIronPython、JScriptに加えLispやScalaといった動的言語の開発も進められています。SilverlightとDLRの組み合わせを使用することで、開発者は好きな言語を選んでアプリケーションの開発が可能となります。
2つ目の利点については、少し説明が必要でしょうか。
DLR上に作成されたアプリケーションは、CLRから動的に呼び出して実行することができます。つまり、C#やVisual Basicといった言語からIronPythonやIronRubyで作成されたスクリプトを読み出して実行することができるということです。
この特性を利用して、ユーザーから頻繁に仕様変更が予想される部分や、手軽に変更を行いたい部分を動的言語で実装し、C#やVisual Basicから呼び出します。動的言語を動的な部分と静的な部分をつなぐ「のりしろ」として使用するのです。
リスト9はC#から動的にPythonのコードを実行している例です。
var pythonCode = "1 + 2"; // 1.動的言語の設定 var languageSetup = new LanguageSetup( "IronPython.Runtime.PythonContext, IronPython, " + "Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", "IronPython 2.0", new string[] { "IronPython", "Python", "py" }, new string[] { ".py" } ); var scriptSetup = new ScriptRuntimeSetup(); scriptSetup.DebugMode = true; scriptSetup.LanguageSetups.Add(languageSetup); // 2.動的言語のエンジンを取得 var runtime = new ScriptRuntime(scriptSetup); var scope = runtime.CreateScope(); var engine = runtime.GetEngine("py"); // 3.コードの実行 var sum = engine.Execute(pythonCode, scope);
動的言語をC#などから呼び出す場合は、次の手順で動的言語を読み込む必要があります。
- 動的言語の設定
- 動的言語のエンジンを取得
- コードの実行
例えばコード中の pythonCode は IronPython のソースコードを格納した文字列です。プログラム中でソースコードをサーバーからダウンロードして実行することで、C# や Visual Basic で記述された既存のSilverlightプログラムをコンパイルすることなく動作を変更することもできますし、Excelの計算式のようにユーザーにプログラムの動作を定義してもらうといった使い方もできます。
C#やVisual Basicで業務アプリケーションを作成している場合は、C#やVisual Basicといった強い型付け言語をメインにプログラムを作成し、動的に変更したい一部を動的言語で作成するというシナリオが思い浮かびます。
SilverlightとHTML DOMの連携
Silverlightでは、SilverlightをホストしているHTMLの要素を操作したり、HTML(JavaScript)からSilverlightの要素を操作することができます。つまりJavaScriptの代わりにPythonやRubyといった言語からSilverlightを通じてHTML DOMを操作することもできるということです。
少し例を見てみましょう。リスト10はSilverlight Dynamic Languages SDKに含まれるslコマンドで生成したHTMLに、textBox1とbutton1というオブジェクトを追加した例です。
<html xmlns="http://www.w3.org/1999/xhtml" > <head> <title>Silverlight Template</title> 略 </head> <body> <input type="text" id="textBox1" /> <input type="button" id="button1" /> 略 <object data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%"> <param name="source" value="python.xap"/> 略 </body> </html>
HTMLがロードされたときに、textBox1にメッセージを表示し、ボタンがクリックされたときにメッセージボックスを表示するコードをIronPythonを使って作成したいと思います。コードの例はリスト11のようになります。
from System.Windows import Application from System import EventHandler from System.Windows.Browser import HtmlPage from System.Windows.Browser.HtmlPage import Document def Button1_Click(sender, event): HtmlPage.Window.Alert("ボタンクリック"); class App: def __init__(self): Document.textBox1.value = "Hello Python"; handler = EventHandler(Button1_Click) Document.Button1.AttachEvent("onclick", handler) App()
Silverlightでは、System.Windows.Browser名前空間のクラスを使うことでHTML DOMにアクセスすることができます。IronPythonの初期化処理ではtextBox1にHello Pythonという文字列を表示し、ボタンがクリックされたときにメッセージボックスを表示するため、Button1_Clickというイベントハンドラが呼び出されるように設定します。
まとめ
こうみると、インタラクティブな要素以外にも、現在の業務アプリケーションを作成する上で必須と言える機能が多く含まれる開発基盤としてSilverlightは大きな役割を持っていることが分かります。
特に大きいのは、C#やVisual BasicといったCLRの言語を使用してアプリケーションを作成することでCLRによるコンパイル時の型解決の恩恵を享受しつつ、動的言語との連携で柔軟にアプリケーションの動作を変更できるということです。
ぜひ一度Silverlightによるアプリケーションの開発を試してみてください。その開発生産性の高さに驚くかもしれませんよ。