• 追加された行はこの色です。
  • 削除された行はこの色です。
#title(ASP.NETでAjaxを使用したWebアプリケーションを作成する 1)

#navi(.NET プログラミング研究)
#navi(.NETプログラミング研究)

#contents

*ASP.NETでAjaxを使用したWebアプリケーションを作成する 1 [#p66b658c]

「.NETプログラミング研究」の第76号で予告したとおり(かなり間が開いてしまいましたが)、今回から何回かに分けてASP.NETでAjaxを使ったWebアプリケーションを作成する方法を紹介します。今回は、.NETの機能を全く使用しない方法を紹介します。今後は、.NET Framework 2.0から追加されたICallbackEventHandlerインターフェイスを実装する方法と、ASP.NET AJAXを使用する方法を紹介する予定です。

ここでは、荷物の大きさから[[ゆうパックの料金>http://www.post.japanpost.jp/fee/simulator/kokunai/parcel.html]]を調べるWebアプリケーションを作成します。DropDownListで荷物の大きさを選択すると、料金が表示されるようにします。料金の調査はサーバーで行い、その結果をクライアントが受け取り、表示します。

**Ajaxを使用しない方法 [#noajax]

Ajaxを使用した方法と比較するために、まずはAjaxを一切使わない、今まで通りの方法で作成した例を示します。今までどおりの方法とは、ポストバックによってページ全体を更新する方法のことです。

この方法は非常に簡単で、DropDownListのAutoPostBackプロパティをTrueにして、SelectedIndexChangedイベントハンドラを追加し、このイベントハンドラで料金を計算して、結果を表示するだけです。以下にコードを示します。

#code(vbnet){{
<%@ Page Language="VB" %>

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

<script runat="server">

    Protected Sub PackageSizeList_SelectedIndexChanged( _
            ByVal sender As Object, ByVal e As EventArgs)
        Dim ddl As DropDownList = CType(sender, DropDownList)
        If ddl.SelectedValue <> "0" Then
            Dim fee As Integer = _
                Me.GetYoupackFee(Integer.Parse(ddl.SelectedValue))
            ResultLabel.Text = String.Format("料金は {0}円", fee)
        Else
            ResultLabel.Text = ""
        End If
    End Sub

    Public Function GetYoupackFee(ByVal packSize As Integer) As Integer
        If packSize <= 60 Then
            Return 600
        Else If packSize <= 80 Then
            Return 800
        Else If packSize <= 100 Then
            Return 1000
        Else If packSize <= 120 Then
            Return 1200
        Else If packSize <= 140 Then
            Return 1400
        Else If packSize <= 160 Then
            Return 1600
        Else If packSize <= 170 Then
            Return 1700
        Else
            Return -1
        End If
    End Function
    
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>ゆうパック送料検索</title>
</head>
<body>
    <h1>ゆうパック送料検索</h1>
    <p>同一都道府県内への配達、重量30kgまで</p>
    <form id="form1" runat="server">
    <div>
        <asp:Label
            ID="Label1"
            runat="server"
            Text="荷物の大きさ(縦・横・高さの合計): "
            AssociatedControlID="PackageSizeList">
        </asp:Label>
        <asp:DropDownList
            ID="PackageSizeList"
            runat="server"
            AutoPostBack="True"
            OnSelectedIndexChanged="PackageSizeList_SelectedIndexChanged">
            <asp:ListItem Value="0">(選択してください)</asp:ListItem>
            <asp:ListItem Value="60">60cmまで</asp:ListItem>
            <asp:ListItem Value="80">80cmまで</asp:ListItem>
            <asp:ListItem Value="100">100cmまで</asp:ListItem>
            <asp:ListItem Value="120">120cmまで</asp:ListItem>
            <asp:ListItem Value="140">140cmまで</asp:ListItem>
            <asp:ListItem Value="160">160cmまで</asp:ListItem>
            <asp:ListItem Value="170">170cmまで</asp:ListItem>
        </asp:DropDownList>
        <br />
        <asp:Label ID="ResultLabel" runat="server"></asp:Label>
    </div>
    </form>
</body>
</html>
}}

#code(csharp){{
<%@ 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">

    protected void PackageSizeList_SelectedIndexChanged(
        object sender, EventArgs e)
    {
        DropDownList ddl = (DropDownList)sender;
        if (ddl.SelectedValue != "0")
        {
            int fee = this.GetYoupackFee(int.Parse(ddl.SelectedValue));
            ResultLabel.Text = string.Format("料金は {0}円", fee);
        }
        else
        {
            ResultLabel.Text = "";
        }
    }

    public int GetYoupackFee(int packSize)
    {
        if (packSize <= 60)
            return 600;
        else if (packSize <= 80)
            return 800;
        else if (packSize <= 100)
            return 1000;
        else if (packSize <= 120)
            return 1200;
        else if (packSize <= 140)
            return 1400;
        else if (packSize <= 160)
            return 1600;
        else if (packSize <= 170)
            return 1700;
        else
            return -1;
    }

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>ゆうパック送料検索</title>
</head>
<body>
    <h1>ゆうパック送料検索</h1>
    <p>同一都道府県内への配達、重量30kgまで</p>
    <form id="form1" runat="server">
    <div>
        <asp:Label
            ID="Label1"
            runat="server"
            Text="荷物の大きさ(縦・横・高さの合計): "
            AssociatedControlID="PackageSizeList">
        </asp:Label>
        <asp:DropDownList
            ID="PackageSizeList"
            runat="server"
            AutoPostBack="True"
            OnSelectedIndexChanged="PackageSizeList_SelectedIndexChanged">
            <asp:ListItem Value="0">(選択してください)</asp:ListItem>
            <asp:ListItem Value="60">60cmまで</asp:ListItem>
            <asp:ListItem Value="80">80cmまで</asp:ListItem>
            <asp:ListItem Value="100">100cmまで</asp:ListItem>
            <asp:ListItem Value="120">120cmまで</asp:ListItem>
            <asp:ListItem Value="140">140cmまで</asp:ListItem>
            <asp:ListItem Value="160">160cmまで</asp:ListItem>
            <asp:ListItem Value="170">170cmまで</asp:ListItem>
        </asp:DropDownList>
        <br />
        <asp:Label ID="ResultLabel" runat="server"></asp:Label>
    </div>
    </form>
</body>
</html>
}}

ゆうパックの計算は、GetYoupackFeeメソッドで行っています。このメソッドは、今後も使用していきます。

**.NETの機能を使用せずに、Ajaxを使用する方法 [#nodotnet]

Ajaxでは、上記の例のようにサーバーにポストバックしてページ全体を更新するのではなく、JavaScriptのようなクライアントスクリプトがサーバーと非同期通信を行い、動的にページの一部を更新します。

ここでは、Ajaxを使って、上の例と同じ事を行ってみましょう。ここで紹介する方法は、Webサービス以外は、.NET Frameworkの機能を一切使用しておらず、必要なJavaScriptのコードは全て自分で記述します。今後このメルマで、JavaScriptの知識をあまり必要としない、より簡単な方法を紹介する予定ですが、それらの方法で自動的に作成されるJavaScriptのコードも、基本的には、ここで紹介するコードと同様のことを行っているはずです。

まず、ゆうパックの料金を取得するためのWebサービスを作成します。Webサービスの作り方は前々号(第76号)で説明しましたので、ここでは説明しません。ここでは、以下のようなコードのWebサービスを"WebService.asmx"というファイル名で作成します。GetYoupackFeeメソッドの内容は、先ほどのものと同じです。

#code(vbnet){{
<%@ WebService Language="VB" Class="WebService" %>

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

<WebService(Namespace := "http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _  
Public Class WebService
    Inherits System.Web.Services.WebService 
    
    <WebMethod()> _
       Public Function GetYoupackFee(ByVal packSize As Integer) As Integer
        If packSize <= 60 Then
            Return 600
        ElseIf packSize <= 80 Then
            Return 800
        ElseIf packSize <= 100 Then
            Return 1000
        ElseIf packSize <= 120 Then
            Return 1200
        ElseIf packSize <= 140 Then
            Return 1400
        ElseIf packSize <= 160 Then
            Return 1600
        ElseIf packSize <= 170 Then
            Return 1700
        Else
            Return -1
        End If
    End Function
End Class
}}

#code(csharp){{
<%@ WebService Language="C#" Class="WebService" %>

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

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService  : System.Web.Services.WebService
{
    [WebMethod]
    public int GetYoupackFee(int packSize)
    {
        if (packSize <= 60)
            return 600;
        else if (packSize <= 80)
            return 800;
        else if (packSize <= 100)
            return 1000;
        else if (packSize <= 120)
            return 1200;
        else if (packSize <= 140)
            return 1400;
        else if (packSize <= 160)
            return 1600;
        else if (packSize <= 170)
            return 1700;
        else
            return -1;
    }
}
}}

また、Web.configを以下のように書き換えて、WebサービスにHTTP GETでアクセスできるようにします。詳しくは、前々号をご覧ください。

#pre{{
<configuration>
  <system.web>
    <webServices>
      <protocols>
        <add name="HttpPost"/>
        <add name="HttpGet"/>
      </protocols>
    </webServices>
  </system.web>
</configuration>
}}

次に、メインとなるページを作成します。.NETの機能は一切使いませんので、「Ajaxを使用しない方法」と比べ、.NETのコードは全て削除し、HTMLの部分だけを使用することにします(ただ、DropDownListのAutoPostBackプロパティはFalseに戻します)。

また、JavaScriptの記述は別のファイル"ajax.js"で行いますので、<script>タグを追加して、その設定をしています。

補足:ここでは前のコードと比較する意味であえてASPXファイルとし、LabelやDropDownListコントロールを使っていますが、その必要はありません(むしろ無駄です)。普通のHTMLに、"PackageSizeList"というIDの<select>タグと、"ResultLabel"というIDの<span>タグがあれば十分です。

#code(vbnet){{
<%@ Page Language="VB" %>

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

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>ゆうパック送料検索</title>
    <script type="text/javascript" src="ajax.js"></script>
</head>
<body>
    <h1>ゆうパック送料検索</h1>
    <p>同一都道府県内への配達、重量30kgまで</p>
    <form id="form1" runat="server">
    <div>
        <asp:Label
            ID="Label1"
            runat="server"
            Text="荷物の大きさ(縦・横・高さの合計): "
            AssociatedControlID="PackageSizeList">
        </asp:Label>
        <asp:DropDownList
            ID="PackageSizeList"
            runat="server">
            <asp:ListItem Value="0">(選択してください)</asp:ListItem>
            <asp:ListItem Value="60">60cmまで</asp:ListItem>
            <asp:ListItem Value="80">80cmまで</asp:ListItem>
            <asp:ListItem Value="100">100cmまで</asp:ListItem>
            <asp:ListItem Value="120">120cmまで</asp:ListItem>
            <asp:ListItem Value="140">140cmまで</asp:ListItem>
            <asp:ListItem Value="160">160cmまで</asp:ListItem>
            <asp:ListItem Value="170">170cmまで</asp:ListItem>
        </asp:DropDownList>
        <br />
        <asp:Label ID="ResultLabel" runat="server"></asp:Label>
    </div>
    </form>
</body>
</html>
}}

#code(csharp){{
<%@ Page Language="C#" %>

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

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>ゆうパック送料検索</title>
    <script type="text/javascript" src="ajax.js"></script>
</head>
<body>
    <h1>ゆうパック送料検索</h1>
    <p>同一都道府県内への配達、重量30kgまで</p>
    <form id="form1" runat="server">
    <div>
        <asp:Label
            ID="Label1"
            runat="server"
            Text="荷物の大きさ(縦・横・高さの合計): "
            AssociatedControlID="PackageSizeList">
        </asp:Label>
        <asp:DropDownList
            ID="PackageSizeList"
            runat="server">
            <asp:ListItem Value="0">(選択してください)</asp:ListItem>
            <asp:ListItem Value="60">60cmまで</asp:ListItem>
            <asp:ListItem Value="80">80cmまで</asp:ListItem>
            <asp:ListItem Value="100">100cmまで</asp:ListItem>
            <asp:ListItem Value="120">120cmまで</asp:ListItem>
            <asp:ListItem Value="140">140cmまで</asp:ListItem>
            <asp:ListItem Value="160">160cmまで</asp:ListItem>
            <asp:ListItem Value="170">170cmまで</asp:ListItem>
        </asp:DropDownList>
        <br />
        <asp:Label ID="ResultLabel" runat="server"></asp:Label>
    </div>
    </form>
</body>
</html>
}}

一番肝心の部分である、Webサービスにアクセスして料金を取得し、ページにその結果を表示する作業は、JavaScriptで行います。Webサービスと非同期で通信するには、XMLHttpRequestを使用します。また、Webサービスが返したXMLを解析するには、XMLDocumentオブジェクトを取得し、利用します。詳しくは、「[[AJAX:Getting Started>http://developer.mozilla.org/ja/docs/AJAX:Getting_Started]]」等を参考にしてください。

ここでは、以下のようなJavaScriptのコードを"ajax.js"に記述します。makeRequest関数などは、「[[AJAX:Getting Started>http://developer.mozilla.org/ja/docs/AJAX:Getting_Started]]」で紹介されているコードをほぼそのまま利用させていただきました。

#code(javascript){{
var msgElement, listElement;

//onloadイベントハンドラを追加
if (window.addEventListener)
{
    window.addEventListener("load", onLoad, false);
}
else if (window.attachEvent)
{
    window.attachEvent("onload", onLoad);
}       
else
{
    window.onload = onLoad;
}

//onloadイベントハンドラ
function onLoad()
{
    msgElement = document.getElementById("ResultLabel");
    listElement = document.getElementById("PackageSizeList");
    
    if (window.addEventListener)
    {
        listElement.addEventListener("change", onChange, false);
    }
    else if (window.attachEvent)
    {
        listElement.attachEvent("onchange", onChange);
    }
    else
    {
        listElement.onchange = onChange;
    }
}

//リストのonchangeイベントハンドラ
function onChange()
{
    if (listElement.value == "0")
    {
        msgElement.innerHTML = "";
        return;
    }
    
    msgElement.innerHTML = "読み込み中...";

    //Webサービスにアクセスする
    var uri = "WebService.asmx/GetYoupackFee?packSize=" + listElement.value;
    if (!makeRequest(uri))
    {
        msgElement.innerHTML = "XMLHTTPインスタンスの作成に失敗しました。";
    }
}

//XMLHttpRequestオブジェクト生成
function makeRequest(url)
{
    var http_request = false;

    if (window.XMLHttpRequest)
    {
        // Mozilla, Safari,...
        http_request = new XMLHttpRequest();
        if (http_request.overrideMimeType)
        {
            http_request.overrideMimeType('text/xml');
        }
    }
    else if (window.ActiveXObject)
    {
        // IE
        try
        {
            http_request = new ActiveXObject("Msxml2.XMLHTTP");
        }
        catch (e)
        {
            try
            {
                http_request = new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch (e)
            {
            }
        }
    }

    if (!http_request)
    {
        return false;
    }
    
    http_request.onreadystatechange = function()
    {
        alertContents(http_request);
    };;
    http_request.open('GET', url, true);
    http_request.send(null);
    return true;
}

function alertContents(http_request)
{
    if (http_request.readyState == 4)
    {
        var ret;
        
        //正しく受信できたかしらべる
        if (http_request.status == 200)
        {
            //XMLを解析する
            var doc = http_request.responseXML;
            var node = doc.getElementsByTagName('int').item(0);
            var fee = node.firstChild.nodeValue;
            ret = "料金は " + fee + "円";
        }
        else
        {
            ret = "正しく取得できませんでした。";
        }
        
        //結果を表示
        msgElement.innerHTML = ret;
    }
}
}}

補足:上記の例では、onloadやonchangeイベントハンドラの追加でかなり面倒なことをしていますが、window.onloadやonchange属性を使用して、もっと簡単にすることもできます。詳しくは、「[[方法 : ASP.NET Web サーバー コントロールにクライアント スクリプト イベントを追加する>http://msdn2.microsoft.com/ja-jp/library/7ytf5t7k(VS.80).aspx]]」などをご覧ください。

当然のことですが、このようにAjaxでは、JavaScriptの知識がかなり必要になります。しかし、.NET Framework 2.0以降では、より簡単な方法も用意されています。次回からは、それらを紹介していく予定です。

**参考 [#z57fa47e]

-[[An Introduction to AJAX Techniques and Frameworks for ASP.NET - The Code Project>http://www.codeproject.com/Ajax/IntroAjaxASPNET.asp]]
-[[クライアント スクリプトを使用する ASP.NET Web ページのプログラミング>http://msdn2.microsoft.com/ja-jp/library/50b7y38h(VS.80).aspx]]

**コメント [#q1984f69]
#comment

//これより下は編集しないでください
#pageinfo([[:Category/.NET]] [[:Category/ASP.NET]],2007-10-23 (火) 02:26:38,DOBON!,2008-07-04 (金) 02:29:58,DOBON!)

[ トップ ]   [ 新規 | 子ページ作成 | 一覧 | 単語検索 | 最終更新 | ヘルプ ]