Observerクラスとサーバー連携
では次に、Observerという機能を使用することによって、画面の更新処理をもっと簡単に記述する例を見てみよう。
せっかくなので、データをサーバー側から取得するようにしてみよう(本サンプルのソースコードはこちらからダウンロードできる)。作成する手順としては、先の例と同じように、プロジェクトを作成した後、ScriptManagerで「MicrosoftAjaxTemplates.js」を追加する。
次に、サーバーからデータを返すWebサービスを作成しよう。とりあえず「NameとAgeを持つPersonクラスのインスタンスを配列で返す」という動きにする。プロジェクトに新しく「Webサービス」を追加する(既定では「WebService1.asmx」というファイル名になる)。
まずサーバーとクライアント間でやりとりするためのデータ構造として、string型のNameプロパティとint型のAgeプロパティを持つEmployeeクラスを定義する。コードは次のようになる。
public class Employee
{
public string Name { get; set; }
public int Age { get; set; }
}
Employeeクラスが定義できたら、WebService1クラスにJavaScriptと連携してデータを取得するメソッドGetEmployeesを定義する。
まず、ファイルの先頭に「using System.Web.Script.Services;」を追加し、WebService1クラスに「ScriptService」属性を追加する。処理の内容はとりあえず「渡されたパラメータに合わせて検索を行う」といった処理は行わず、常に同じデータを返すという単純な動きにしておこう。
JavaScriptからも呼び出せるように、GetEmployeesメソッドにもScriptMethod属性も追加しておく。そうすると、メソッドのコードは次のようになる。
[WebMethod]
[ScriptMethod(UseHttpGet=true)]
public List<Employee> GetEmployees()
{
return new List<Employee> {
new Employee { Name = "鈴木", Age = 30 },
new Employee { Name = "田中", Age = 35 }
};
}
それでは、Default.aspxに戻ってHTMLのテンプレートを記述しよう。今回はObserverクラスと連携するため、先ほどの例に比べると少し複雑になる。まずbody要素に、いくつかのXML名前空間の別名を追加しておく。
<body xmlns:sys="javascript:Sys" xmlns:dataview="javascript:Sys.UI.DataView" sys:activate="*">
テンプレート自体のコードは次のようになる。
<div id="imagesList" class="sys-template" sys:attach="dataview" dataview:data="{{ imagesArray }}" style="border:1px solid #ddd;">
<p>
名前:{{ Name }}<br />
年齢:{{ Age }}
</p>
</div>
先ほどの例に比べると、いくつかの属性が追加されている。
まず「sys-template」というクラスが追加されており「 sys:attach="dataview"」という属性が追加されている(ここで使用されている「sys」という接頭辞は、さきほどbody要素の属性に記述したものを使用している)。
そして、最後に「dataview:data="{{ imagesArray }}"」という属性が追加されている。これはJavaScript上のimagesArrayという変数と、このテンプレートをひもづけるという処理だ。imagesArrayという変数は、後でJavaScript内で使用する。
では、次にJavaScriptを記述しよう。まず、imagesArray変数を定義する。
var imagesArray = [];
次に、Observerクラスを使用して、imagesArrayに対する変更を監視する処理を記述する。コードは次のようになる。
Sys.Observer.makeObservable(imagesArray);
実は、この2行のJavaScriptで、HTML上のテンプレートとJavaScript上のimagesArray変数がひもづけられたことになる。後はimagesArrayに要素を追加したり削除したりすることで、HTMLも自動的に更新されるようになる。
それでは、まずimagesArrayの要素を削除する処理を記述する。とりあえず先頭の要素を削除するという処理にしておく。イベントハンドラから呼び出すため、onDeleteButtonClickという名前の関数で定義しておく。
function onDeleteButtonClick() {
imagesArray.remove(imagesArray[0]);
}
最後にサーバーからデータをXMLで取得してimagesArrayに追加する処理を記述しよう。JavaScriptのコードからWebサービスにアクセスしてデータを取得する処理も、ASP.NET AJAXであれば非常に簡単に記述できる。
まず、JavaScriptからGetEmployeesメソッドにアクセスするためのクラスを生成するために、ScriptManagerにWebService1.asmxへの参照を追加する。
これだけの処理で、WebService1.asmxにアクセスするためのJavaScriptのクラスが自動生成される。インテリセンスも利用可能だ。
では、こうして生成したクラスを使用して、imagesArrayに要素を追加する処理を追加しよう。こちらもイベントハンドラから呼び出すため、onInsertButtonClickという名前の関数で定義しておく。
function onInsertButtonClick() {
var ws = new WebApplication2.WebService1.GetEmployees(function(result) {
for (var i = 0; i < result.length; i++) {
imagesArray.add(result[i]);
}
});
}
GetEmployeesメソッドに渡す引数は、データ取得後に呼び出す処理を記述した関数になる。ここで、GetEmployeesの戻り値を、imagesArrayに追加している。
さて、あとは画面に追加ボタンと削除ボタンを追加し、それぞれクリックしたときにonInsertButtonClick関数とonDeleteButtonClick関数が呼び出されるようにすれば完成だ。ビルドして実行し、実際に動作することを確認してみよう。
このサンプルで行ったことをまとめると次のようになる。
- サーバーからデータ(XML or JSON)を取得する
- そのデータをテンプレートとバインドしている変数に代入する
- 自動的にDOM(画面)が更新される
Webサービスからデータを取得するロジックと、取得したデータをレンダリングするロジックが、明確に分離できているのが分かると思う。たとえば、レンダリングの仕方を変える場合でも、JavaScriptは一切変更する必要がないのだ。
このように、ASP.NET 4.0においては、Ajaxを使用したクライアントサイドのレンダリングも、非常に簡潔に記述できるようになっているのである。ASP.NET 3.5で追加されたWebサービス連携と組み合わせて使用すれば、高機能なAjaxアプリケーションが簡単に作れるようになるはずだ。
サンプルソースコード: WebApplication2.zip