WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

リストコントロール上の選択結果を取得

by WebSurfer 2012年11月9日 00:28

注意:
DOM Level 3 Events がサポートされていない IE8 以前に対応するには、下の「2013/2/7 追加」に書いた対応が必要です。

ASP.NET のリストコントロール DropDownList, ListBox, RadioButtonList, CheckBoxList において、ユーザーが選択した ListItem に設定された Value プロパティや Text プロパティの値を、クライアント側で取得する方法です。

ListItem の Text プロパティの値

クライアント側で取得するので、ASP.NET がサーバーコントロールから生成した html コードがどのようになっているかを把握する必要があります。

DropDownList と ListBox からレンダリングされる html コードは、select 要素と option 要素で構成されます。ListItem の Value と Text は option 要素の value 属性と内部 HTML として設定されます。

RadioButtonList と CheckBoxList からレンダリングされる html コードは、input 要素と label 要素で構成されます。ListItem の Value は input 要素の value 属性として、Text は label 要素の内部 HTML として設定されます。(2012/11/10 追記: .NET 3.5 の CheckBoxList には問題があります。下の注記参照)

DropDownList, ListBox, RadioButtonList, CheckBoxList から生成された html コードの詳細は 実験室 のページのソースを見てください。下に提示したサンプルを実際に動かして試せるようしてあります。

クライアントスクリプトは JavaScript を使用することになりますが、JavaScript だけでは自分には難しいので、jQuery のセレクタの助けを借ります。

JavaScript + jQuery のサンプルコードは JQUERY API のページにもあります。.change() あたりが参考になるかもしれません。

一応、以下のようなサンプルコードを書いてみました。実験室 で実際に動かせます。

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title>リストコントロール上の選択結果を取得</title>
  <script src="Scripts/jquery-1.4.1.js" type="text/javascript">
  </script>
  <script type="text/javascript">
  //<![CDATA[
    $(document).ready(function () {

      $("#DropDownList1").change(function () {
        var str = $("#DropDownList1 option:selected").val() +
          " " + 
          $("#DropDownList1 option:selected").text();
          $("#Div1").text(str);
        });

        $("#ListBox1").change(function () {
          var str = "";
          $("#ListBox1 option:selected").each(function () {
            str += $(this).val() + " " + 
            $(this).text() + " ";
          });
          $("#Div2").text(str);
        });

        $("#RadioButtonList1").change(function () {
          var str = 
            $("#RadioButtonList1 input:checked").val() +
            " " +
            $("#RadioButtonList1 input:checked + label").text();
          $("#Div3").text(str);
        });

        $("#CheckBoxList1").change(function () {
          var str = "";
          $("#CheckBoxList1 input:checked").each(function () {
            str += $(this).val() + " " +
              $(this).next().text() + " ";
          });
          $("#Div4").text(str);
        });
      });
  //]]>
  </script>
</head>
<body>
  <form id="form1" runat="server">
  <table style="width: 500px;">
    <tr>
      <td style="vertical-align: top;">
        <asp:DropDownList id="DropDownList1" 
          runat="server">
          <asp:ListItem Value="00" Text="Red" />
          <asp:ListItem Value="01" Text="Green" />
          <asp:ListItem Value="02" Text="Blue" />
        </asp:DropDownList>
      </td>
      <td style="vertical-align: top;">
        <asp:ListBox id="ListBox1" 
          Rows="3" 
          SelectionMode="Multiple" 
          runat="server">
          <asp:ListItem Value="10" Text="Red" />
          <asp:ListItem Value="11" Text="Green" />
          <asp:ListItem Value="12" Text="Blue" />
        </asp:ListBox>    
      </td>
      <td style="vertical-align: top;">
        <asp:RadioButtonList id="RadioButtonList1" 
          runat="server">
          <asp:ListItem Value="20" Text="Red" />
          <asp:ListItem Value="21" Text="Green" />
          <asp:ListItem Value="22" Text="Blue" />
        </asp:RadioButtonList>
      </td>
      <td style="vertical-align: top;">
        <asp:CheckBoxList id="CheckBoxList1" 
          runat="server">
          <asp:ListItem Value="30" Text="Red" />
          <asp:ListItem Value="31" Text="Green" />
          <asp:ListItem Value="32" Text="Blue" />
        </asp:CheckBoxList>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">
        <div id="Div1"></div>
      </td>
      <td style="vertical-align: top;">
        <div id="Div2"></div>
      </td>
      <td style="vertical-align: top;">
        <div id="Div3"></div>
      </td>
      <td style="vertical-align: top;">
        <div id="Div4"></div>
      </td>
    </tr>
  </table>
  </form>
</body>
</html>

----- 2012/11/10 注記追加 -----

.NET 3.5 では、CheckBoxList からレンダリングされる html コードで、input 要素に value 属性が設定されません。その状態で、上記 jQuery のコードで value を取得すると "on" となります。(注: MDN のドキュメント <input type="checkbox"> によると "value 属性が省略された場合は、チェックボックスの既定値は on " とのことです)

実験室は .NET 3.5 なので試してみてください。CheckBoxList のみ on Red とか on Green と表示されるはずです。.NET 4 では問題ありません。上の画像は .NET 4 のものです。

IE8 以前、IE9 でも互換モードでは、ListBox と CheckBoxList をクリックしても、最初は無反応となります。理由は、最初に表示されたときはイベントにハンドラがアタッチされないからです。何度かクリックしているとアタッチされて反応するようになります。理由は不明。ちなみに、Firefox 16.0.2, Chrome 23.0.1271.64 m Safari 5.1.7, Opera 12.02 は問題なかったです。

----- 2013/2/7 追加 -----

先に、IE9 では期待通り動くが IE8 以前では、ListBox と CheckBoxList が、最初のうち無反応と書きました。違いは何かを考えてみると、IE9 では DOM Level 3 Events がサポートされているのに対し、IE8 以前ではサポートされてないことを思い出しました。

試しに、addEventListener メソッドと attachEvent メソッドを使い分けてハンドラ(リスナー)をアタッチするようにしてみました。

その結果、ListBox は期待通り動くようになったものの、RadioButtonList と CheckBoxList が全く無反応になってしまいました。(IE8 以前での話しです。IE9 は問題ありません)

Microsoft が公開しているドキュメント change | onchange event (Internet Explorer) によると、change イベントが発生する条件として以下の記述があります。(← Microsoft の記事はリンク切れになってしまいました。クリックすると MDN の記事 HTMLElement: change event に遷移しますが、それとは内容が異なります)

To invoke this event, do one of the following:

  1. Choose a different option in a select object using mouse or keyboard navigation.
  2. Alter text in the text area and then navigate out of the object.

ということは、RadioButtonList, CheckBoxList はそれぞれ input type=checkbox, input type=radio 要素なので、change イベントは発生しないということになります。

change イベントに代えて click イベントにリスナーをアタッチすることで RadioButtonList, CheckBoxList の選択を変更を捕捉できます。

以下のコードが対応版です。実験室 で実際に動かせます。

オリジナルとの違いは、(1) ListBox については、change イベントにリスナーをアタッチするのを jQuery 任せにせず自分でコードを書いて addEventListener メソッドと attachEvent メソッ ドを使い分けたこと、(2) RadioButtonList, CheckBoxList については、change イベントの代わりに click イベントにリスナーをアタッチしたことです。

なお、なぜ ListBox では jQuery によるリスナーのアタッチがうまくいかず、上記 (1) の操作が必要かは不明です。

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>WebSurfer's Page - 実験室</title>
  <script src="Scripts/jquery-1.4.1.js" type="text/javascript">
  </script>
  <script type="text/javascript">
  //<![CDATA[
  $(document).ready(function () {
    $("#DropDownList1").change(function () {
      var str = $("#DropDownList1 option:selected").val() +
        " " +
        $("#DropDownList1 option:selected").text();
      $("#Div1").text(str);
    });

    function listenerForListBox() {
      var str = "";
      $("#ListBox1 option:selected").each(function () {
        str += $(this).val() + " " + $(this).text() + " ";
      });
      $("#Div2").text(str);
    }

    var element = document.getElementById("ListBox1");
    if (element.addEventListener) {
      element.addEventListener('change', 
                               listenerForListBox, false);
    } else if (element.attachEvent) {
      element.attachEvent('onchange', listenerForListBox);
    }

    $("#RadioButtonList1").click(function () {
      var str =
        $("#RadioButtonList1 input:checked").val() +
        " " +
        $("#RadioButtonList1 input:checked + label").text();
      $("#Div3").text(str);
    });

    $("#CheckBoxList1").click(function () {
      var str = "";
      $("#CheckBoxList1 input:checked").each(function () {
        str += $(this).val() + " " +
          $(this).next().text() + " ";
      });
      $("#Div4").text(str);
    });
  });
  //]]>
  </script>
</head>
<body>
  <form id="form1" runat="server">
  <table style="width: 500px;">
    <tr>
      <td style="vertical-align: top;">
        <asp:DropDownList id="DropDownList1" 
          runat="server">
          <asp:ListItem Value="00" Text="Red" />
          <asp:ListItem Value="01" Text="Green" />
          <asp:ListItem Value="02" Text="Blue" />
        </asp:DropDownList>
      </td>
      <td style="vertical-align: top;">
        <asp:ListBox id="ListBox1" 
          Rows="3" 
          SelectionMode="Multiple" 
          runat="server">
          <asp:ListItem Value="10" Text="Red" />
          <asp:ListItem Value="11" Text="Green" />
          <asp:ListItem Value="12" Text="Blue" />
        </asp:ListBox>    
      </td>
      <td style="vertical-align: top;">
        <asp:RadioButtonList id="RadioButtonList1" 
          runat="server">
          <asp:ListItem Value="20" Text="Red" />
          <asp:ListItem Value="21" Text="Green" />
          <asp:ListItem Value="22" Text="Blue" />
        </asp:RadioButtonList>
      </td>
      <td style="vertical-align: top;">
        <asp:CheckBoxList id="CheckBoxList1" 
          runat="server">
          <asp:ListItem Value="30" Text="Red" />
          <asp:ListItem Value="31" Text="Green" />
          <asp:ListItem Value="32" Text="Blue" />
        </asp:CheckBoxList>
      </td>
    </tr>
    <tr>
      <td style="vertical-align: top;">
        <div id="Div1"></div>
      </td>
      <td style="vertical-align: top;">
        <div id="Div2"></div>
      </td>
      <td style="vertical-align: top;">
        <div id="Div3"></div>
      </td>
      <td style="vertical-align: top;">
        <div id="Div4"></div>
      </td>
    </tr>
  </table>
  </form>
</body>
</html>

Tags: ,

JavaScript

IIS Express をインストールしました

by WebSurfer 2012年10月8日 16:10

今さらながらですが、IIS 7.5 Express を Microsoft の Download Center から入手してインストールして使ってみました。

IIS Express

IIS Express の概要の説明は、ここに書くまでもないので省略します。知りたい方は、ScottGu 氏のブログの翻訳 IIS Express の紹介 を見てください。手抜きですみません。(笑) 

インストールの仕方も、ここに書くまでもないので省略します。ダウンロードしたファイルをエクスプローラーで探して、それをダブルクリックすれば自動的にインストールされます。

ただし、インストールしただけでは Visual Studio 2010 SP1 から自動的に使えるようにはなりませんので注意してください。以下の画像にあるように、ソリューションエクスプローラーで、プロジェクトを右クリックして出てくるコンテキストメニューで、[IIS Express を使用する (U)...]に設定してやる必要があります。その他の詳細については、ScottGu 氏の別のブログ VS 2010 SP1 (Beta) and IIS Express を参考にしてください。

IIS Express を使用する

ところで、一番気になっていた IIS とワーカープロセスのアカウントですが、少なくともデフォルトでは、ASP.NET 開発サーバーと同じでした。即ち、その PC にログインしているユーザーのアカウントになります。

少なくとも自分が探した限りでは、IIS Express のワーカープロセスのアカウントを、IIS と同じにするオプションは見つかりませんでした。なので、ASP.NET 開発サーバーでは動いていたのが IIS では動かないという問題は、IIS Express でも起こり得るので注意が必要です。

ちなみに、IIS の匿名ユーザーアカウント、ワーカープロセスのアカウント/グループについては以下のページを参照してください。

IIS 7.0 での組み込みユーザーとグループ アカウントとは

Application Pool Identities

IIS 7 のアクセス許可

ASP.NET 開発サーバーおよび IIS Express の場合は、上記のページで説明されている IIS のアカウント/グループが、すべて PC にログインしているユーザーのものになります。

その他、気をつけなければならないのがアプリケーション名の設定です。具体的にどういうことかと言うと、以下のとおりです。

Web サイトプロジェクトで、例えば、物理パス C:\WebSite\AppDirectory に Web アプリケーションがあるとします。

Visual Studio から [ファイル(F)] ⇒ [Web サイトを開く(E)] で表示されるダイアログから Web アプリケーションを開いて、そのルート直下の Default.aspx を要求する場合、デフォルトでは以下のような URL になります。

ASP.NET 開発サーバ: http://localhost:xxxxx/AppDirectory/Default.aspx
IIS Express: http://localhost:xxxxx/Default.aspx
ローカルIIS: http://<サイト名>/<アプリ名のエイリアス>/Default.aspx

「ASP.NET 開発サーバ」と「ローカル IIS」の場合は AppDirectory と <アプリ名のエイリアス> の名前を同じに設定すれば "/<アプリ名のエイリアス>/default.aspx" というサイトルート相対パスが使えます。

ところが、「IIS Express」の場合は "/<アプリ名のエイリアス>/default.aspx" というサイトルート相対パスは使えません。パスの設定によってはリンクが切れて、「ASP.NET 開発サーバー」や「ローカル IIS」で動いていたものが「IIS Express」では動かない(または、その逆)ということが起こり得ます。

Web アプリケーションプロジェクトの場合は「IIS Express」を使って /<アプリ名のエイリアス>/default.aspx というように設定する方法があるのは見つけましたが、Web サイトプロジェクトの方はギブアップしました。

なので、自分が設定する方法を知らないだけという可能性は否定し切れません。(笑)

Tags:

DevelopmentTools

非同期 HTTP ハンドラ

by WebSurfer 2012年9月23日 13:18
2018/3/8 追記:
この記事と同じ機能を持つ非同期 HTTP ハンドラを .NET 4.5 から利用できるようになった async / await を利用して実装してみました。その記事は「非同期 HTTP ハンドラ (2)」にありますので興味があれば見てください。この記事の方法が時代遅れなのが分かると思います。

ASP.NET の非同期プログラミングモデルには、(1) 非同期ページ、(2) 非同期 HTTP ハンドラ、(3) 非同期 HTTP モジュールの 3 つがあります。このうち、(2) 非同期 HTTP ハンドラを使って Web サービスのメソッドを非同期に呼び出す場合について、いろいろ不明な点があったので、それらを調べて分かったことを備忘録として書いておきます。

MSDN マガジンの March 2007 の記事「ASP.NET の非同期プログラミングを使ったスケール変換可能なアプリケーション (Wicked Code: Scalable Apps with Asynchronous Programming in ASP.NET)」が、非同期プログラミングの目的、メリット、仕組みなどをサンプルコードを使って詳しく説明しており、大変参考になりました。(2017/5/20 追記:記事は .chm ファイル形式で保存されており、MSDN Magazine Issues and Downloads からダウンロードして読むことができます)

(2015/12/29 追記:非同期プログラミングのメリット、仕組みなど基本的な説明を書いた新しい記事 ASP.NET の非同期/待機の概要を紹介しておきます。.NET 4.5 以降で利用できる async / await を使うことが前提です)

ただし、その中の非同期 HTTP ハンドラのサンプルは複雑すぎて、その仕組みなどがよく分かりませんでした。特に分からなかったのは以下の点です。

  1. Web サービスのメソッドを非同期で呼び出すメソッドをどのように生成するか(例えば、Web サービスのメソッドが HelloWorld だったとすると、BeginHelloWorld と EndHelloWorld をどのよ���に作成するか)。
  2. 非同期 HTTP ハンドラのコードで非同期呼び出しのためのメソッド(上の例で言うと、BeginHelloWorld メソッドと EndHelloWorld メソッド)をどのように呼び出すか。
  3. BeginProcessRequest メソッドの第 2 引数として渡されるコールバックメソッドのデリゲートは何か。
  4. EndProcessRequest メソッドが呼び出される仕組みとそのタイミングはどうなっているか。

という訳で、簡単なサンプルを作って上記の点について調べてみました。下の画像は、説明のためにここに紹介したサンプルを実行したときのものです。

非同期 HTTP ハンドラの使用

サンプルとして、以下の Web サービスを非同期 HTTP ハンドラを使って利用することを考えます。これに定義されているのは HelloWorld メソッドだけです。同期 HTTP ハンドラではこれを呼べば済みますが、非同期 HTTP ハンドラを使う場合は非同期で HelloWorld メソッドを呼び出し、結果を処理しなければなりません。

非同期呼び出しのために、BeginHelloWorld メソッドと EndHelloWorld メソッドが必要ですが、それらはどのように作ればよいのでしょうか?

(1) Web サービス (141-HelloWorldWebService.asmx)

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

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Threading;

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class _141_HelloWorldWebService  : WebService {

  [WebMethod]
  public string HelloWorld(int callDuration) 
  {
    Thread.Sleep(callDuration);
    return String.Format(
      "Hello World from WebService. Call Time: {0}",
      callDuration);
  }    
}

答えはサービスプロキシを定義することです。と言っても、自力でコードを書く必要はなく、Visual Studio を使ってサービス参照を追加するか、または、SDK にある Wsdl.exe ツールを利用してサービスプロキシクラスを自動生成すれば OK です。ここでは、後者の Wsdl.exe ツールを利用した例を書きます。

Wsdl.exe ツールの詳しい使用方法は、MSDN ライブラリの XML Web サービス プロキシの作成 にあります。これを参考に、上記の Web サービスの URL とプロキシのコードの出力先のファイル名をパラメータとして、コマンドラインから Wsdl.exe を実行します。以下の画像のような感じです。

wsdl.exe を使ってプロキシクラスを生成

この結果、上記 (1) の Web サービスからプロキシクラス HelloWorldWebService.cs が自動生成されます。コードは以下のとおりです(一部省略、改行等をしています)。

(2) Web サービスプロキシ (HelloWorldWebService.cs)

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Serialization;

[System.CodeDom.Compiler.GeneratedCodeAttribute(
  "wsdl", "2.0.50727.3038")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(
  Name="_141_HelloWorldWebServiceSoap", 
  Namespace="http://tempuri.org/")]
public partial class _141_HelloWorldWebService : 
  System.Web.Services.Protocols.SoapHttpClientProtocol 
{
  private System.Threading.SendOrPostCallback 
    HelloWorldOperationCompleted;
    
  public _141_HelloWorldWebService() 
  {
    this.Url = 
      "http://msdntestnew/141-HelloWorldWebService.asmx";
  }
    
  public event HelloWorldCompletedEventHandler 
    HelloWorldCompleted;

  [System.Web.Services.Protocols.SoapDocumentMethodAttribute(
    "http://tempuri.org/HelloWorld", 
    RequestNamespace="http://tempuri.org/", 
    ResponseNamespace="http://tempuri.org/", 
    Use=System.Web.Services.Description.SoapBindingUse.Literal,
    ParameterStyle=
      System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
  public string HelloWorld(int callDuration) 
  {
    object[] results = this.Invoke(
        "HelloWorld", new object[] { callDuration });
    return ((string)(results[0]));
  }
    
  public System.IAsyncResult BeginHelloWorld(
    int callDuration, 
    System.AsyncCallback callback, 
    object asyncState) 
  {
    return this.BeginInvoke(
      "HelloWorld", 
      new object[] { callDuration }, 
      callback, 
      asyncState);
  }
    
  public string EndHelloWorld(System.IAsyncResult asyncResult) 
  {
    object[] results = this.EndInvoke(asyncResult);
    return ((string)(results[0]));
  }

  // ・・・中略・・・

}

上に示したプロキシクラスに、SoapHttpClientProtocol.BeginInvoke メソッドSoapHttpClientProtocol.EndInvoke メソッド をラップした BeginHelloWorld メソッドと EndHelloWorld メソッドが生成されているのが分かるでしょうか?

このファイル HelloWorldWebService.cs を、Web アプリケーションのルート直下の App_Code フォルダに置けばプロキシは使用可能になり、それに定義されている BeginHelloWorld メソッドと EndHelloWorld メソッドを利用して、以下のように非同期 HTTP ハンドラを作成できます。

(3) 非同期 HTTP ハンドラ (141-HelloWorldAsyncHandler2.ashx)

<%@ WebHandler Language="C#" 
    Class="_141_HelloWorldAsyncHandler2" %>

using System;
using System.Web;
using System.Threading;

public class _141_HelloWorldAsyncHandler2 : IHttpAsyncHandler
{
  private HttpContext _context;
  private _141_HelloWorldWebService _serviceProxy;
    
  // これが呼び出されることはない。万一呼び出されたら例外
  // をスローして自爆する
  public void ProcessRequest (HttpContext context) 
  {
    throw new InvalidOperationException();
  }
 
  public bool IsReusable 
  {
    get { return false; }
  }

  // まず最初にこのメソッドが呼ばれる。
  // cb には ASP.NET が内部で生成したコールバックメソッド
  // void OnAsyncHandlerCompletion(System.IAsyncResult)
  // のデリゲートが渡される。これが EndProcessRequest メ
  // ソッドを呼び出す。extraData には null が渡される。
  public IAsyncResult BeginProcessRequest(
    HttpContext context,
    AsyncCallback cb,
    Object extraData)
  {
    this._context = context;

    context.Response.Write(
      "<p>BeginProcessRequest:<br />" +
      " IsThreadPoolThread is " +
      Thread.CurrentThread.IsThreadPoolThread +
      "<br />" +
      " ManagedThreadId is " +
      Thread.CurrentThread.ManagedThreadId.ToString() +
      "</p>");

    _serviceProxy = new _141_HelloWorldWebService();

    // 終了すると引数 cb に設定したコールバックデリゲート
    // が起動される。その中で EndProcessRequest メソッドが
    // 呼び出される。
    return _serviceProxy.BeginHelloWorld(3000, cb, null);
  }

  // 引数 ar には BeginProcessRequest メソッドの戻り値であ
  // る IAsyncResult オブジェクトが渡される。
  public void EndProcessRequest(IAsyncResult ar)
  {
    _context.Response.Write(
      "<p>EndProcessRequest:<br />" +
      " IsThreadPoolThread is " +
      Thread.CurrentThread.IsThreadPoolThread +
      "<br />" +
      " ManagedThreadId is " +
      Thread.CurrentThread.ManagedThreadId.ToString() +
      "</p>");

    string result = _serviceProxy.EndHelloWorld(ar);

    _context.Response.Write("<p>" + result + "</p>");
  }
}

非同期 HTTP ハンドラでは、BeginProcessRequest メソッドが最初に実行されます。引数 context には現在の HttpContext オブジェクトへの参照が、cb には ASP.NET が内部で生成したコールバックメソッドのデリゲートが、extraData には null が渡されます。

BeginProcessRequest メソッドでは、プロキシクラスを初期化して BeginHelloWorld メソッドを呼び出し、HelloWorld メソッドの非同期実行を開始します。非同期実行の開始後すぐに制御が戻って、ここまでの処理に使用していたスレッドはスレッドプールに戻されます。

BeginHelloWorld メソッドの第 1 引数は HelloWorld メソッドに渡されます(ここでは、待機時間 3000 即ち 3 秒を渡しています)。第 2 引数 cb には BeginProcessRequest メソッドの引数 cb に渡されたコールバックメソッドのデリゲートがそのままコピーされます。第 3 引数は BeginProcessRequest メソッドの戻り値、即ち EndProcessRequest メソッドの引数 ar に渡される IAsyncResult オブジェクトから、AsyncState プロパティを使って取得できるデータですが、ここでは使用しないので null としています。

ここで覚えておくべきことは、BeginHelloWorld メソッドの第 2 引数として渡されたコールバックメソッドのデリゲートが実行されると EndProcessRequest メソッドが実行されることです(逆に言えば、コールバックメソッドが実行されないとフリーズしてしまう)。

非同期処理の完了後、コールバックメソッドのデリゲートが実行され、EndProcessRequest メソッドが呼び出されます。その際、スレッドプールから空いているスレッドを取得して EndProcessRequest メソッドを実行します。この時、引数 ar には BeginProcessRequest メソッドの戻り値である IAsyncResult オブジェクトが渡されます。 EndProcessRequest メソッドの中で、EndHelloWorld メソッドを実行し、Web サービスからの応答をその戻り値から取得します。EndProcessRequest メソッドの終了後、制御がコールバックメソッドに戻って全体のタスクが終了します。

上記の非同期 HTTP ハンドラを iframe の src 属性に設定した aspx ページの例は以下の通りです。一番上の画像は、以下の aspx ページの実行結果です。

(4) aspx ページ (141-HelloWorldAsyncHandler.aspx)

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
    <iframe src="141-HelloWorldAsyncHandler2.ashx" 
      id="iframe2"
      width="400px" 
      height="200px">
    </iframe>
  </form>
</body>
</html>

Tags:

ASP.NET

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年5月  >>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar