あたもこトップ

Windows アプリケーションのような動作をASP.NET で表面的に真似る

このエントリーをはてなブックマークに追加

ここで説明するメッセージボックス制御では、技術的には Javascript でポストバックを行っている。 Javascript からフォームに対してサブミット(ポストバック)するだけであれば、難しいことはない。

今回は、以下のような一般的(?)な状況を例に考える。

● 複数の入力項目を持つWebフォームで登録ボタンクリックでデータベースへ登録する
● 入力された情報がデータベース上に存在しない場合はそのまま登録する
● 入力された情報が既にデータベース上に存在すれば確認ダイアログを表示する
● OKボタンがクリックされた場合にのみ、その情報を上書きし、キャンセルボタンの場合は何もしない。

Windows アプリケーションでは容易だが、ASP.NET では、サーバーとブラウザでそれぞれの処理を実行させつつ 実行順序を制御する必要があるので、悩むことも多いだろう。

[ポイント]

・ データベースへの問い合わせはWebサーバーで行う
・ 確認ダイアログはブラウザ上で出力させる
・ JavaScriptからポストバックを行う

サンプルコード(枠組のみ)

では、実際のサンプルコードを見てみる。なお、データベースへの登録処理などは 今回の本題ではないので記述していない。詳細はサンプルコード中のコメントを参照のこと。

[ASPX]
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="Button" />
    </div>
    </form>
[VB]
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        If IsPostBack Then

            'Javascriptからのsubmitはポストバックとして認識される

            ' 上書きする(OK)ボタンがクリックされた場合
            Dim update As String = Page.Request.QueryString.Get("update")
            If (update = "true") Then

                '----------------------------------------------
                ' TODO:ここで、データを上書きする処理を行う
                '----------------------------------------------

                '(後始末)
                ' 次のポストバックでこのルートを通らないようにするために
                ' アップデートのために追加したGET パラメータ(update)をaction属性から除去する
                Dim formid As String = Me.Form.ClientID
                Dim cScript As String = formid + ".action = ""Default.aspx"";"

                'JavaScriptの埋め込み(画面表示前に実行させる)
                ClientScript.RegisterClientScriptBlock(Me.GetType(), "clientscript", cScript, True)

            End If

        End If

    End Sub

    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click

        Dim confirm As Boolean

        '--------------------------------------------------------
        ' TODO:ここにデータベースに存在するか確認する処理を記述する
        '--------------------------------------------------------

        If (True) Then
            ' 確認ダイアログを出力させる
            confirm = True
        Else
            '確認ダイアログを出力させない
            confirm = False
        End If

        'マスターページを使っている場合、formタグのidがaspnetFormとなるので、
        '確実に取得するためには、Form.ClientIDプロパティからIDを取得する
        Dim formid As String = Me.Form.ClientID

        If (confirm) Then
            ' 確認ダイアログを出力するスクリプト
            ' POST先は自分自身(Default.aspx)
            Dim sScript As String = "if(confirm(""上書きしますか?"")){ " + _
                                        formid + ".method = ""post"";" + _
                                        formid + ".action = ""Default.aspx?update=true"";" + _
                                        formid + ".submit();" + _
                                    "}"
            'JavaScriptの埋め込み
            ClientScript.RegisterStartupScript(Me.GetType(), "startup", sScript, True)

            ' ClientScript.RegisterStartupScriptメソッドで登録した場合、ブラウザでの描画完了後に
            ' 登録したJavaScriptが実行される
            '
            ' ここでは、OKボタンが押されたことをGETパラメーター(update)で通知する

        Else

            '--------------------------------------------------------
            ' TODO:ここに、データを登録する処理を記述する
            '--------------------------------------------------------

        End If

    End Sub
[C#]
    protected void Page_Load(object sender, EventArgs e)
    {
        if (IsPostBack)
        {
            // Javascriptからのsubmitはポストバックとして認識される

            // ここで、GETパラメーター(update)がTrueの場合には、フォーム上のデータを
            // データベース上に上書きする処理を記述する

            // 上書きする(OK)ボタンがクリックされた場合
            string update = Page.Request.QueryString.Get("update");
            if (update == "true") {
            
               //-------------------------------------------------
               // TODO:ここで、データを上書きする処理を行う
               //-------------------------------------------------
 
                //(後始末)
                // 次のポストバックでこのルートを通らないようにするために
                // アップデートのために追加したGET パラメータ(update)をaction属性から除去する
                string formid = this.Form.ClientID;
                string cScript = formid + ".action = \"Default.aspx\";";

                // JavaScriptの埋め込み(画面表示前に実行させる)
                ClientScript.RegisterClientScriptBlock(this.GetType(), "clientscript", cScript, true);
            }

        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        Boolean confirm;

        //-------------------------------------------------
        // TODO:ここにデータベースに存在するか確認する処理を記述する
        //-------------------------------------------------

        if (true) {
            // 確認ダイアログを出力させる
            confirm = true;
        } else {
            // 確認ダイアログを出力させない
            confirm = false;
        }

        // マスターページを使っている場合、formタグのidがaspnetFormとなるので、
        // 確実に取得するためには、Form.ClientIDプロパティからIDを取得する
        string formid = this.Form.ClientID;

        if (confirm) {
            // 確認ダイアログを出力するスクリプト
            string sScript = "if(confirm(\"上書きしますか?\")){ " + 
                                     formid + ".method = \"post\";" + 
                                     formid + ".action = \"Default.aspx?update=true\";" + 
                                     formid + ".submit();" + 
                                 "}else{" + 
                                     "" + 
                                 "}";

            // JavaScriptの埋め込み
            ClientScript.RegisterStartupScript(this.GetType(), "startup", sScript, true);

            // ClientScript.RegisterStartupScriptメソッドで登録した場合、ブラウザでの描画完了後に
            // 登録したJavaScriptが実行される
            //
            // OKがクリックされるとGETパラメーター(update)を付けて、ポストバックする

        } else {
        
            //-------------------------------------------------
            // TODO:ここに、データを登録する処理を記述する
            //-------------------------------------------------
        }
    }

F5 で再表示を行った場合の問題点

今回のサンプルでは上書きするかの判断を GET パラメーター ( update ) で行っているが、 Page_Load イベントで上書き処理を行った状態で、再表示 ( F5 ) を行うと再度上書き処理が行われてしまう (GET パラメーターも再度送られる)。 対応方法は色々あると思うが、解決法の1つとして、PageLoad イベントで更新登録したあとで、ClientScript.RegisterClientScriptBlock で スクリプトを埋め込む代わりに、Response.Redirect (URL にはGet パラメーターをつけない)で自分自身にリダイレクションさせる。 するとブラウザでは F5 で再表示を行っても GET パラメーターをつけずにリクエストを送るようになる。 クライアントとブラウザ間で往復回数が増えるが、簡単な対処方法である。

[おまけ] ポストバックにしたくないとき

今回は Javascript からポストバックするようにしたが、例えば"キャンセル"が選択された場合は、 ポストバックにせずに単にページ遷移するとした場合は、form.submit ではなく、以下のように location.href を使用する。

location.href = "Default.aspx";

※ asp.net とは関係なく、javascript の話

関連

プログラミング
ウィンドウズ
データベース
サーバー構築
ソフトウェア