連載:Microsoft AJAX Library&JavaScriptプログラミング

第4回 MS AJAX LibでAJAX対応コントロールを開発しよう(後編)

山田 祥寛(http://www.wings.msn.to/
2008/02/08
Page1 Page2 Page3 Page4

[3]Behaviorオブジェクトを編集する

 続いて、Behaviorオブジェクトを編集する。エクステンダ・クラスと同様、必要最低限のコードはデフォルトで生成されているので、適宜、必要な部分のみを追記/編集すればよい。

// MyAjaxLib名前空間を宣言
Type.registerNamespace("MyAjaxLib");

// MyAjaxLib.AjaxDialogButtonBehaviorクラスのコンストラクタを定義
MyAjaxLib.AjaxDialogButtonBehavior = function(element) {

  // 基底クラスのコンストラクタをコール
  MyAjaxLib.AjaxDialogButtonBehavior.initializeBase(
    this, [element]);

  // ServicePath/ServiceMethod/Keyプロパティの値を
  // 格納するためのプライベート変数を宣言
  this._ServicePath = '';
  this._ServiceMethod = '';
  this._Key = '';
}

// MyAjaxLib.AjaxDialogButtonBehaviorクラスのメンバを宣言
MyAjaxLib.AjaxDialogButtonBehavior.prototype = {

  // コンポーネントを初期化するための
  // initializeメソッドをオーバーライド
  initialize : function() {

    // 基底クラスのinitializeメソッドをコール
    MyAjaxLib.AjaxDialogButtonBehavior.callBaseMethod(
      this, 'initialize');

    // ターゲット要素にclickイベント・ハンドラ(_onClick)を適用
    $addHandler(
      this.get_element(),
      'click',
      Function.createDelegate(this, this._onClick)
    );
  },

  // コンポーネントの終了処理を行うための
  // disposeメソッドをオーバーライド
  dispose : function() {
    MyAjaxLib.AjaxDialogButtonBehavior.callBaseMethod(
      this, 'dispose');
  },

  // ServicePathプロパティにアクセスするための
  // アクセサ・メソッドを定義
  get_ServicePath : function() {
    return this._ServicePath;
  },

  set_ServicePath : function(value) {
    if (this._ServicePath !== value) {
      this._ServicePath = value;
      this.raisePropertyChanged('ServicePath');
    }
  },

  // ServiceMethodプロパティにアクセスするための
  // アクセサ・メソッドを定義
  get_ServiceMethod : function() {
    return this._ServiceMethod;
  },

  set_ServiceMethod : function(value) {
    if (this._ServiceMethod !== value) {
      this._ServiceMethod = value;
      this.raisePropertyChanged('ServiceMethod');
    }
  },

  // Keyプロパティにアクセスするためのアクセサ・メソッドを定義
  get_Key : function() {
    return this._Key;
  },

  set_Key : function(value) {
    if (this._Key !== value) {
      this._Key = value;
      this.raisePropertyChanged('Key');
    }
  },

  // Closedイベントを追加/削除するための
  // addXxxxx/removeXxxxxメソッドを定義
  add_Closed : function(handler) {
    this.get_events().addHandler('Closed', handler);
  },

  remove_Closed : function(handler) {
    this.get_events().removeHandler('Closed', handler);
  },

  // ターゲット要素がクリックされたときの実処理を定義
  _onClick : function(e) {

    // 指定されたXML Webサービスにアクセス
   Sys.Net.WebServiceProxy.invoke(
      this._ServicePath,
      this._ServiceMethod,
      false,
      {
        key: this._Key
      },
      Function.createDelegate(this, this._onSuccess),
      Function.createDelegate(this, this._onFailure)
    );

    // Closedイベント・ハンドラを取得し、
    // 存在する場合にのみハンドラを呼び出し
    var h = this.get_events().getHandler('Closed');
    if (h) {
      h(this, Sys.EventArgs.Empty);
    }
    return false;
  },

  // XML Webサービスの呼び出しが成功したときに
  // 実行されるコールバック関数
 _onSuccess : function(result,context,method) {
    // サービス・メソッドの結果をメッセージボックスに表示
    window.alert(result);
  },

  // XML Webサービスの呼び出しが失敗したときに
  // 実行されるコールバック関数
  _onFailure : function(ex,context,method) {
    // 例外メッセージをメッセージボックスに表示
    window.alert(ex.get_message());
  }
};

// AjaxControlToolkit.BehaviorBaseクラスを継承する
// MyAjaxLib.AjaxDialogButtonBehaviorクラスを登録
MyAjaxLib.AjaxDialogButtonBehavior.registerClass(
  'MyAjaxLib.AjaxDialogButtonBehavior',
   AjaxControlToolkit.BehaviorBase);
リスト2 AjaxDialogButtonコントロールのクライアント側の挙動を定義するBehaviorオブジェクト(AjaxDialogButtonBehavior.js)

 プロパティ/イベントの定義については前回でも紹介しているので、そちらを参照いただくとして、注目していただきたいのは白字の部分だ。

 通常、ASP.NET AJAXでAjax機能を実装する場合は、ブリッジ機能を利用するのが一般的だ。ブリッジ機能に関する詳細は、別稿「.NET TIPS:[ASP.NET AJAX]クライアントサイド・スクリプトからXML Webサービスを非同期呼び出しするには?(クライアントサイド編)」でも紹介しているが、ここで紹介した方法には、次のようないくつかの制限がある。

  • サービス・クラス/メソッド名をハード・コーディングしなければならない
  • .asmxファイルをScriptManager.Scriptsプロパティに登録する必要がある

 このような制限は、個別のアプリケーション機能を実装するに際しては、殊更に問題になるものではないが、汎用的なコントロールを作成するとなれば話は別だ。本サンプルのように、サービス・クラス/メソッド名はコントロールの利用者に決定させたいという場合、前述の別稿で紹介した方法では対応できない*1

*1 厳密には、与えられた文字列を動的に解釈/実行するevalメソッドを利用すればできないことはない。しかしevalメソッドはパフォーマンス的にも不利であり、通常、このような方法は用いるべきではない。

 もちろん、サービス・クラス/メソッド名を最初から固定してしまうという選択肢もあるかもしれないが、コントロールの汎用性を考えれば、できるだけコントロールの利用者に対する制約は少なくしておくに越したことはないだろう。また、そもそも.asmxファイルをScriptManagerコントロールに登録するなどという決まりきった手続きは、コントロール利用者に委ねるのではなく、コントロールの内部で隠ぺいしてしまうのが好ましい。

 そこで登場するのが、Sys.Net.WebServiceProxyクラスだ。このクラスは、XML Webサービスにアクセスするための「汎用的な」プロキシ・クラスを生成するための機能を提供する。Sys.Net.WebServiceProxyクラスを利用することで、.asmxファイルをScriptManagerクラスに登録することなく、かつ、サービス・クラス/メソッドの名前をプログラム的(動的)に決定することが可能になる。

 Sys.Net.WebServiceProxyクラスが提供するメソッドは、唯一、invokeメソッドだけだ。invokeメソッドの構文は以下のとおり。

Sys.Net.WebServiceProxy.invoke(
  .asmxファイルのパス
  ,サービス・メソッドの名前,
  [,HTTP GETを使用するか
  [,サービス・メソッドに渡す引数(ハッシュ形式)
  [,成功コールバック
  [,例外コールバック
  [,コンテキスト値
  [,タイムアウト時間]]]]]]
);
Sys.Net.WebServiceProxyクラスのinvokeメソッドの構文

 invokeメソッド、および、コールバック関数の引数の部分は、前述の別稿で紹介した内容と重なっているので、そちらを参照いただくとよい。ここでは、invokeメソッドでは.asmxファイルの名前、メソッド名を引数として指定できるようになったことで、サービス・クラス/メソッド名を動的に変更できるようになっている点に注目していただきたい。前述したような理由で、Extenderコントロールに対してAjax機能を実装する際には、通常、このinvokeメソッドを使用するのが一般的である*2

*2 Control Toolkitで提供されているAutoCompleteCascadingDropDownなどといったコントロールも同様の仕組みを利用している。

 さて、以上の構文を踏まえてリスト2の挙動を確認してみると、ここでは、

ServicePath/ServiceMethodプロパティで指定された.asmxファイルのサービス・メソッドに対して、引数key(Keyプロパティ)を渡し、その結果をメッセージボックスに表示している

ということになる。ScriptManagerコントロールによって自動生成されたプロキシ・クラスを利用するのに比べると、やや記述が冗長に思えるかもしれないが、やっていることはほとんど同じであることがお分かりいただけるだろう。

 以上で、Extenderコントロールの実装は完了だ。前回の解説を参考にビルドからアセンブリの配置までを行ってほしい。また、ツールボックスに対して、今回作成したAjaxDialogButtonコントロールを登録しておこう。

■AjaxDialogButtonコントロールを利用する

 続いて、作成したAjaxDialogButtonコントロールを、実際にWebフォームから確認してみよう。

[1]新規のXML Webサービス・クラスを定義する

 AjaxDialogButtonコントロールを利用するには、クライアント側からキー値を受け取り、任意のメッセージ文字列を返すXML Webサービス・クラスを用意しておく必要がある。

 ここでは、与えられたキー値に基づいて、「こんにちは、<キー値>さん!」という文字列を返すサービス・メソッドを定義している。

<%@ WebService Language="C#" Class="DialogButtonAjax" %>

using System;
using System.Web;
using System.Web.Script.Services;
using System.Web.Services;
using System.Web.Services.Protocols;

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService()]
public class DialogButtonAjax  : System.Web.Services.WebService {

  [WebMethod]
  public string GetMessage(String key) {
    return String.Format("こんにちは、{0}さん!", key);
  }
}
<%@ WebService Language="VB" Class="DialogButtonAjax" %>

Imports System.Web
Imports System.Web.Script.Services
Imports System.Web.Services
Imports System.Web.Services.Protocols

<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<ScriptService()> _
Public Class DialogButtonAjax
  Inherits System.Web.Services.WebService

  <WebMethod()> _
  Public Function GetMessage(ByVal key As String) As String
    Return String.Format("こんにちは、{0}さん!", key)
  End Function
End Class
リスト3 AjaxDialogButtonコントロールから利用されるXML Webサービス(DialogButtonAjax.asmx。上:C#、下:VB)

 サービス・メソッドのシグニチャについては、先ほど述べたとおりだ。また、ブリッジ機能固有の構文については、別稿「.NET TIPS:[ASP.NET AJAX]クライアントサイド・スクリプトからXML Webサービスを非同期呼び出しするには?(サーバサイド編)」で紹介しているので、併せて参照いただきたい。

[2]新規のWebフォームを作成する

 続いては、新規のWebフォーム(DialogButtonAjax.aspx)を作成し、フォーム・デザイナから以下の図2の要領でサーバ・コントロールを配置する。また、それぞれのコントロールに対しては、表2の内容でプロパティ値を設定しておこう。


図2 Webフォーム(DialogButtonAjax.aspx)のレイアウト

コントロール名(ID値) プロパティ名 設定値
ScriptManager(manager)
Button(btnDialog) Text 表示
AjaxDialogButtonExtender(adbe) Key MS Ajax Lib
ServiceMethod GetMessage
ServicePath DialogButtonAjax.asmx
TargetControlID btnDialog
表2 図2で配置したコントロールとその設定

 AjaxDialogButtonコントロール(AjaxDialogButtonExtender)のTargetControlIDプロパティは、メッセージボックス機能を付与するButtonコントロールを指定する。これによって、Buttonコントロール「btnDialog」にAjaxDialogButtonコントロールの機能が追加されたことになるわけだ。

 なお、前回も紹介したように、AjaxDialogButtonコントロールのそのほかのプロパティを設定する場合、(AjaxDialogButtonコントロールそのものではなく)関連付けたButtonコントロールのプロパティとして設定する必要がある点に注意してほしい。本稿の場合であれば、Buttonコントロールのプロパティ・ウィンドウに「adbe(AjaxDialogButtonExtender)」という項目が追加されているので、この項目の配下から個々の値を設定する必要がある。

 以上の手順を終えたら、さっそく、DialogButtonAjax.aspxを実行してみよう。冒頭の図1のように、[表示]ボタンをクリックすることでサービス・メソッドから取得したメッセージがメッセージボックスに表示されれば成功だ。


 INDEX
  Microsoft AJAX Library&JavaScriptプログラミング
  第4回 MS AJAX LibでAJAX対応コントロールを開発しよう(後編)
    1.Ajax対応のExtenderコントロールを作成しよう
  2.AjaxDialogButtonコントロールのBehaviorオブジェクト
    3.Control Toolkit標準のBehaviorオブジェクトを活用しよう
    4.DialogButtonExternalコントロールのBehaviorオブジェクト
 
インデックス・ページヘ  「Microsoft AJAX Library&JavaScriptプログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間