• 追加された行はこの色です。
  • 削除された行はこの色です。
*ASP.NET AJAXを使う [#d37ae965]
#title(Microsoft ASP.NET AJAXを使う)

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

#contents

*Microsoft ASP.NET AJAXを使う [#d37ae965]

ASP.NETでAjaxを使ったWebアプリケーションを作成する方法を前々号から紹介してきました。前回はICallbackEventHandlerインターフェイスを実装する方法を紹介し、JavaScriptを全て自分で記述する方法と比べ、多少楽をすることができました。それでもやはりJavaScriptのコードを自分で書くことは必要で、JavaScriptの知識が必要でした。

ここで紹介する[[Microsoft ASP.NET AJAX>http://asp.net/ajax/default.aspx]](開発コード名"Atlas")を使用すれば、極端に言えば、自分でJavaScriptのコードを一行も書くことなく、Ajaxを使用したページを作成することができます。自分でJavaScriptのコードを書かなければならない場合でも、大幅に簡略化できます。

ASP.NET AJAXはマイクロソフトが公開している無料のフレームワークであり、ASP.NET 2.0に対応しています。現在最新のバージョンは1.0であり、ここで説明に使用しているASP.NET AJAXのバージョンも1.0です。

**ASP.NET AJAXをインストールする [#z541599a]

ASP.NET AJAXをインストールするには、.NET Framework 2.0以上が必要です。
ASP.NET AJAXをインストールするには.NET Framework 2.0が必要ですので、まず.NET Framework 2.0がインストールされていることを確認してください。

まず、ASP.NET AJAXをダウンロードします。MSIファイルとして提供されています。以下のページからダウンロードできます。
ASP.NET AJAXは「[[ASP.NET AJAX Downloads : The Official Microsoft ASP.NET 2.0 Site>http://www.asp.net/ajax/downloads/]]」からダウンロードできます。「ASP.NET 2.0 AJAX Extensions」と「ASP.NET AJAX Control Toolkit」がありますが、とりあえずはAJAX Extensionsだけで結構です。Control Toolkitをインストールする時も、AJAX Extensionsをインストールした後にしてください。

-AJAX : The Official Microsoft ASP.NET 2.0 Site
-http://go.microsoft.com/fwlink/?LinkId=75350
ダウンロードされたファイルは、"ASPAJAXExtSetup.msi"のようなファイル名になっているでしょう。このファイルをダブルクリックして、インストールを開始してください。インストールするには、管理者権限が必要です。また、前のバージョンのASP.NET AJAXがインストールされている場合は、アンインストールしてから新しいバージョンをインストールしてください。

ここでは、「ASP.NET 2.0 AJAX Extensions」をダウンロードしてください。「ASP.NET AJAX Control Toolkit」もインストールしたい場合は、「ASP.NET 2.0 AJAX Extensions」をインストールした後にしてください。
ASP.NET AJAXのインストールに成功すると、Visual Studio 2005(またはVisual Web Developer Express Edition)にASP.NET AJAX用のプロジェクトのテンプレートがインストールされます。Visual Studioで「新しいWebサイト」ダイアログを表示させると、「ASP.NET AJAX-Enabled Web Site」というテンプレートが見つかるはずです。また、ツールボックスに「AJAX Extensions」というタブが追加され、幾つかのコンポーネントが登録されます。

ダウンロードしたMSIファイルを使ってインストールします。インストールするには、管理者権限が必要です。また、前のバージョンのASP.NET AJAXがインストールされている場合は、これをアンインストールしてから新しいバージョンをインストールしてください。
&ref(selecttemplate.png,nolink,ASP.NET AJAX-Enabled Web Siteテンプレート);

ASP.NET AJAXがインストールされると、Visual Studio 2005(またはVisual Web Developer Express Edition)にASP.NET AJAX用のプロジェクトのテンプレートがインストールされます。Visual Studioで「新しいWebサイト」ダイアログを表示させると、「ASP.NET AJAX-Enabled Web Site」というテンプレートが見つかるでしょう。また、ツールボックスに「AJAX Extensions」というタブが追加され、幾つかのコンポーネントが登録されます。
&ref(toolbox.png,nolink,ツールボックスの「AJAX Extensions」);

このようなテンプレートでプロジェクトを作成したり、「AJAX Extensions」タブにあるコンポーネントをページに配置したりすると、Web.configに必要な設定が書き込まれます。Visual Studio(またはVisual Web Developer Express Edition)をインストールしていない場合は、Web.configの設定を自分で書き込む必要があります。どのように書き込むかのサンプルが、ASP.NET AJAXをインストールしたフォルダにあります。ASP.NET AJAXは、通常「C:\Program Files\Microsoft ASP.NET」のようなパスにインストールされ、サンプルのWeb.configはそれ以下の「C:\Program Files\Microsoft ASP.NET\ASP.NET 2.0 AJAX Extensions\v1.0.61025\web.config」のようなパスにあります。
ASP.NET AJAXを使用するには、Web.configに適切な設定が必要です。テンプレート「ASP.NET AJAX-Enabled Web Site」を使ってプロジェクトを作成したときは、適切なWeb.configが用意されるため問題ありません。

**ASP.NET AJAXを使う [#n4f31489]
テンプレート「ASP.NET AJAX-Enabled Web Site」を使わなかった時でも、「AJAX Extensions」タブにあるコントロールをページに配置したときに、Web.configに必要な設定が書き込まれるということになっていますが、これが完全ではないようです。よって、テンプレート「ASP.NET AJAX-Enabled Web Site」で作成されるWeb.configを参考にして、自分で記述しないとエラーが出るかもしれません。

**ASP.NET AJAXを使って、WebサービスのメソッドをJavaScriptから呼び出す [#p124f866]
Visual Studioをインストールしていない場合は、Web.configの設定をすべて自分で書き込む必要があります。どのように記述するかのサンプルが、ASP.NET AJAXをインストールしたフォルダにあります。ASP.NET AJAXは、通常「C:\Program Files\Microsoft ASP.NET」のようなパスにインストールされ、サンプルのWeb.configはそれ以下の「C:\Program Files\Microsoft ASP.NET\ASP.NET 2.0 AJAX Extensions\v1.0.61025\web.config」のようなパスで見つかるでしょう。

ASP.NET AJAXを使うと、まるでWebサービスのメソッドをJavaScriptから直接呼び出すかのように、Webサービスにアクセスすることができます。
**UpdatePanelを使う [#updatepanel]

ここでは、前々号で紹介したアプリケーションと同じものをこの機能を使って実現してみます。
早速ASP.NET AJAXを使ってみましょう。ここでは、前回、前々回と同様、ゆうパックの料金を調べるWebアプリケーションを作成します。

まず、WebサービスのクラスにScriptServiceAttribute属性を適用します。
Visual Studioを使用した場合の手順は、次のようになります。

+メニューの[ファイル]-[新規作成]-[Webサイト]から、「ASP.NET AJAX-Enabled Web Site」テンプレートを使用して、新しいWebサイトを作成します。(「ASP.NET AJAX-Enabled Web Site」テンプレートを使わなかった場合は、Web.configを適当に書き換えてください。)
+Default.aspxのデザインを開きます。ScriptManagerコントロールが一つ配置されていることを確認します。新しいページを作成したなどでScriptManagerが配置されていない場合は、ツールボックスの「AJAX Extensions」タブからScriptManagerをページにドラッグ&ドロップして、配置します。ScriptManagerは必ず1つのページに1つだけ配置します。
+ツールボックスの「AJAX Extensions」タブからUpdatePanelをページにドラッグ&ドロップして、配置します。
+前々号の「[[Ajaxを使用しない方法>../78#noajax]]」で紹介したのと全く同じ方法でコントロールの配置と設定をし、さらに、全く同じコードを記述します。ただしコントロールは、すべてUpdatePanelコントロール内に配置します。具体的なコードは、次のようになります(ここでは、単一ページにしています)。

&ref(updatepanel.png,nolink,UpdatePanelを配置したページのデザイン画面);

#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
        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
    
</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:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <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>
            </ContentTemplate>
        </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>
}}

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

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

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class WebService  : System.Web.Services.WebService
{
    [WebMethod]
<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:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <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>
            </ContentTemplate>
        </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>
}}

もし「ASP.NET AJAX-Enabled Web Site」テンプレートを使用してプロジェクトを作成していないのであれば、Web.configに以下のような設定を追加して、ScriptHandlerFactory HTTPハンドラを登録する必要があります。
以上ですべて終了です。

#pre{{
<system.web>
  <httpHandlers>
    <remove verb="*" path="*.asmx"/>
    <add verb="*" path="*.asmx" type="System.Web.Script.Services.ScriptHandlerFactory" validate="false"/>
  </httpHandlers>
<system.web>
驚くことに、前々回紹介した、Ajaxを使用せずに、今までどおりポストバックを使用する方法と、ほとんど同じになります。コードは全く同じで、違いは、荷物のサイズを選択するDropDownListコントロールと、結果を表示するLabelコントロールがUpdatePanelコントロールの中(<ContentTemplate>の中)に入っていることだけです。自分でJavaScriptを書く必要も、Webサービスを作成する必要もありません。

UpdatePanelコントロールを使うためには、ScriptManagerコントロールが必要です。もしUpdatePanelコントロールを使いたいページにScriptManagerコントロールが無ければ、まずScriptManagerコントロールを追加してから、UpdatePanelコントロールを追加します。ScriptManagerコントロールは、1つのページに1つだけ配置できます。

補足:UpdatePanelコントロールの部分に出力されるHTMLは、<div>で囲まれた状態になります。

**トリガーをUpdatePanelの外に出す [#triggers]

上記の例では全てのコントロールをUpdatePanelコントロール内に入れていましたが、基本的には、変化のある部分だけをUpdatePanelコントロール内に入れた方が良いです。変化のない部分をUpdatePanelコントロール内に入れてしまうと、サーバーは変化のない部分も含めた更新後のHTMLを送信するため、無駄が多くなり、効率的でありません。

UpdatePanelコントロールの中身を更新するためのきっかけとなるコントロール(トリガー)をUpdatePanelの外に出したときは、UpdatePanelのTriggersプロパティにトリガーの情報を追加する必要があります。

実際に上記のコードを改造してみましょう。

+"Label1"と"PackageSizeList"をUpdatePanelの外に出します。
+デザイナで"UpdatePanel1"を選択し、プロパティウィンドウの"Triggers"の右にある「...」ボタンをクリックして、「UpdatePanelTriggerコレクションエディタ」を表示します。
+「追加」ボタンをクリックして、「メンバ」に「AsyncPostBack」を追加します。
+「ControlID」プロパティを"PackageSizeList"とします。つまり、このUpdatePanelを更新するトリガーとなるコントロールに"PackageSizeList"ドロップダウンリストを指定します。
+「EventName」プロパティを"SelectedIndexChanged"とします。つまり、SelectedIndexChangedイベントが発生した時にUpdatePanelが更新されるようにします。(この場合は、何も指定しなくても大丈夫です。)
&ref(triggers.png,nolink,UpdatePanelTriggerコレクションエディタ);
+「OK」ボタンをクリックします。
+以上です。

この改造によって出来上がったコードは、次のようになります。

#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
        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
    
</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:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <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:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <asp:Label ID="ResultLabel" runat="server"></asp:Label>
            </ContentTemplate>
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="PackageSizeList"
                    EventName="SelectedIndexChanged" />
            </Triggers>
        </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>
}}

次に、Webサービスを呼び出すJavaScriptを作成します。
#code(csharp){{
<%@ Page Language="C#" %>

次に、Webサービスを呼び出すページを作成します。コントロールの配置は、今までと同じままとし、ScriptManagerコントロールを一つ配置します。
<!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 id="Head1" runat="server">
    <title>ゆうパック送料検索</title>
</head>
<body>
    <h1>ゆうパック送料検索</h1>
    <p>同一都道府県内への配達、重量30kgまで</p>
    <form id="form1" runat="server">
    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <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:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <asp:Label ID="ResultLabel" runat="server"></asp:Label>
            </ContentTemplate>
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="PackageSizeList"
                    EventName="SelectedIndexChanged" />
            </Triggers>
        </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>
}}

**UpdatePanelの制限 [#jbc89610]

このようにUpdatePanelは非常に簡単で、便利ですが、注意しなければならない点も多々あります。

例えば、UpdatePanelの中に入れることのできないコントロールもあります。TreeView、Menu、WebParts、SubstitutionコントロールはUpdatePanelの中に入れて使うことができません。FileUpload、GridView、DetailsView、Login、PasswordRecovery、ChangePassword、CreateUserWizard、検証(Validation)コントロールは、制限付きでUpdatePanelの中に入れて使うことができます。詳しくは、「[[UpdatePanel Control Overview>http://asp.net/AJAX/Documentation/Live/overview/UpdatePanelOverview.aspx]]」をご覧ください。

今回はこれでおしまいです。次回もASP.NET AJAXについて説明します。

**参考 [#l5014b26]

-[[UpdatePanel Control Overview>http://asp.net/AJAX/Documentation/Live/overview/UpdatePanelOverview.aspx]]
-[[UpdatePanel Control Tutorials>http://asp.net/AJAX/Documentation/Live/tutorials/UpdatePanelTutorials.aspx]]
-[[UpdatePanel Class>http://asp.net/AJAX/Documentation/Live/mref/T_System_Web_UI_UpdatePanel.aspx]]

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

//これより下は編集しないでください
#pageinfo(,2007-10-11 (木) 17:27:24,DOBON!,2007-10-12 (金) 17:44:24,DOBON!)
#pageinfo([[:Category/.NET]] [[:Category/ASP.NET]],2007-11-19 (月) 03:34:51,DOBON!,2008-03-03 (月) 00:36:55,DOBON!)

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