ICallbackEventHandlerの実装
AjaxNotifierコントロールでは、ICallbackEventHandlerインターフェースを実装することで、ASP.NET 2.0のクライアントコールバックメカニズムを利用してサーバへの非同期クライアントコールバックを行います。リスト3に、RaiseCallbackEventメソッドおよびGetCallbackResultメソッドのコードを示します。
protected virtual string GetCallbackResult() { return callbackResult; } protected virtual void RaiseCallbackEvent(string eventArgument) { IDataSource ds = (IDataSource)Page.FindControl(DataSourceID); int notificationId = int.Parse(eventArgument); if (notificationId < 0) notificationId = 1; Page.Session["NotificationId"] = notificationId; if (ds != null) { DataSourceView dv = ds.GetView(string.Empty); dv.Select(DataSourceSelectArguments.Empty, SelectCallback); } }
AjaxNotifierは、DataSourceIDという名前の文字列プロパティを公開します。ページ開発者は、これを必要な表形式データソースコントロールのIDプロパティの値に設定しなければなりません。リスト3に示すように、RaiseCallbackEventメソッドは、ASP.NETの表形式データソースコントロールAPIを使用して、一般的な方法でデータストアからデータを取得します。これについては、このガイドで既に詳しく説明しました。RaiseCallbackEventメソッドの引数には、現在のユーザーに示されている最新の通知のIDを渡します。RaiseCallbackEventメソッドで、このID値をSessionオブジェクトに格納していることに注目してください。この必要性を理解するために、AjaxNotifierコントロールを使ったページを見てみましょう(リスト4)。エンドユーザーがこのページにアクセスすると、図1のダイアログが表示されます。
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="CustomComponents"
Assembly="CustomComponents" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<form id="form1" runat="server">
<custom:AjaxNotifier runat="server" DataSourceID="MySource"
DialogStyle-BackColor="LightGoldenrodYellow"
DialogStyle-BorderColor="Tan" DialogStyle-BorderWidth="1px"
DialogStyle-CellPadding="2" DialogStyle-CellSpacing="0"
DialogStyle-BorderStyle="Groove" DialogStyle-ForeColor="Black"
DialogStyle-GridLines="None" HeaderStyle-BackColor="Tan"
HeaderStyle-Font-Bold="True"
AlternatingItemStyle-BackColor="PaleGoldenrod" />
<asp:SqlDataSource runat="server" ID="MySource"
ConnectionString="<%$ connectionStrings:
MySqlConnectionString %>"
SelectCommand="Select * From Notifications Where Id > @Id">
<SelectParameters>
<asp:SessionParameter Name="Id"
SessionField="NotificationId"
Type="Int32" />
</SelectParameters>
</asp:SqlDataSource>
</form>
</body>
</html>
リスト4のページでは、AjaxNotifierコントロールをSqlDataSourceコントロールにバインドしています。<asp:SqlDataSource>タグのSelectCommand属性には、次のSelectSQLステートメントが含まれています。
Select * From Notifications Where Id > @Id
このSQLステートメントには、@Idという名前のパラメータが含まれています。このパラメータの値は、現在のユーザーに示される最新の通知のIDです。リスト4に示したように、SqlDataSourceコントロールはSessionParameterを使用して、Sessionオブジェクトから通知IDを取得します。そのために、通知IDをSessionオブジェクトに格納しているのです。
<asp:SqlDataSource runat="server" ID="MySource"
ConnectionString="<%$ connectionStrings:MySqlConnectionString %>"
SelectCommand="Select * From Notifications Where Id > @Id">
<SelectParameters>
<asp:SessionParameter Name="Id" SessionField="NotificationId"
Type="Int32" />
</SelectParameters>
</asp:SqlDataSource>
表形式データソースコントロールとポストされたデータとの間でデータをやり取りするための方法は、Sessionオブジェクトだけではありません。この作業を行う他の方法については、『Professional ASP.NET 2.0 Server Control and Component Development』の第27章「Developing Ajax-Enabled Controls and Components:Asynchronous Client Callback」で説明しています。リスト3に示したように、RaiseCallbackEventメソッドは、SelectCallbackメソッドをSelectデータ操作のコールバックとして登録します。このSelectCallbackメソッドの実装をリスト5に示します。このメソッドの主な仕事は、取得したデータレコードを使用してXMLドキュメントを生成し、クライアントに送信することです。つまり、クライアントとサーバは、XML形式でデータをやり取りします。
private void SelectCallback(IEnumerable data) { using (StringWriter sw = new StringWriter()) { using (XmlWriter xw = XmlWriter.Create(sw)) { xw.WriteStartDocument(); xw.WriteStartElement("notification"); IEnumerator iter = data.GetEnumerator(); if (iter.MoveNext()) { PropertyDescriptorCollection col = TypeDescriptor.GetProperties(iter.Current); foreach (PropertyDescriptor pd in col) { if (pd.Name == "Source") xw.WriteElementString("source", (string)pd.GetValue(iter.Current)); else if (pd.Name == "Notification") xw.WriteElementString("summary", (string)pd.GetValue(iter.Current)); else if (pd.Name == "Id") xw.WriteElementString("id", pd.GetValue(iter.Current).ToString()); } } xw.WriteEndElement(); xw.WriteEndDocument(); } callbackResult = sw.ToString(); } }
従って、XMLドキュメントの構造または書式を決めることも、Ajax対応コントロールの開発者の仕事の1つとなります。リスト6に、AjaxNotifierコントロールがサポートするXMLドキュメントの例を示します。
<notification> <id>3</id> <source>John</source> <summary>We'll meet tomorrow morning</summary> </notification>
他のすべてのXMLドキュメントと同じように、このXMLドキュメントも1つのドキュメント要素(<notification>)を持ち、この要素には、<id>、<source>、<summary>の3つの子要素が含まれています。
リスト5に示したように、SelectCallbackメソッドは、『Professional ASP.NET 2.0 Server Control and Component Development』の第24章「Developing Custom Role Providers、Modules、and Principals」で説明したXmlWriterストリーミングAPIを使用してXMLドキュメントを生成します。生成されたXMLドキュメントはStringWriterにロードされます。SelectCallbackメソッドは、まず、XmlWriterのWriteStartDocumentメソッドを呼び出してドキュメントの開始を通知し、XML宣言を生成します。
xw.WriteStartDocument();
次に、WriteStartElementメソッドを呼び出して、<notification>ドキュメント要素の開始タグを書き出します(リスト6を参照)。
xw.WriteStartDocument();
その後、列挙オブジェクトにアクセスし、取得したデータを一般的な方法で列挙できるようにします。
IEnumerator iter = data.GetEnumerator();
続いて、PropertyDescriptionCollectionコレクションを取得します。このコレクションには、取得したレコードのデータフィールドごとに1つのPropertyDescriptorオブジェクトが含まれています。
PropertyDescriptorCollection col =
TypeDescriptor.GetProperties(iter.Current);
次に、これらのPropertyDescriptorオブジェクトを反復処理し、<source>要素、<summary>要素、および<id>要素と、その内容を書き出します。
if (pd.Name == "Source") xw.WriteElementString("source", (string)pd.GetValue(iter.Current)); else if (pd.Name == "Notification") xw.WriteElementString("summary", (string)pd.GetValue(iter.Current)); else if (pd.Name == "Id") xw.WriteElementString("id", pd.GetValue(iter.Current).ToString());
