【答客問】JavaScript修改WebForm DropDownList選項

【案例】

某個ASP.NET WebForm網頁,加入JavaScript動態修改欄位,送出表單時出現錯誤:
(英文版) Invalid postback or callback argument.  Event validation is enabled using <pages enableEventValidation="true"/> in configuration or <%@ Page EnableEventValidation="true" %> in a page.  For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them.  If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.
(中文版) 無效的回傳或回呼引數。已在組態中使用 <pages enableEventValidation="true"/> 或在網頁中使用 <%@ Page EnableEventValidation="true" %> 啟用事件驗證。基於安全性理由,這項功能驗證回傳或回呼引數是來自原本呈現它們的伺服器控制項。如果資料為有效並且是必需的,請使用 ClientScriptManager.RegisterForEventValidation 方法註冊回傳或回呼資料,以進行驗證。

追查後發現問題出在JavaScript為<asp:DropDownList>動態新增了選項。

ASP.NET 2.0+為避免原本Server端管控的下拉選單被駭客加料塞入非預期值,故DropDownList會記下原有選項組合,一旦Client讓該欄位送回選項以外的值,便會觸發錯誤。解決之道是透過RegisterForEventValidation()方法向ASP.NET預告該欄位可能出現的值,如此資料送回時比對吻合就能通過驗證。

用一個範例來說明: WebForm網頁上有一個DropDownList,預先宣告C#及VB.NET兩個ListItem,另外再透過JavaScript加入Ruby及JavaScript兩個新<option>。至於Server端,我們需覆寫Render()方法,加入ClientScript.RegisterForEventValidation(),但此處只註冊JavaScript,以觀察Ruby及JavaScript兩個選項產生的結果。程式碼如下:

<%@ Page Language="C#" %>
 
<!DOCTYPE html>
 
<script runat="server">
    protected void btn_Click(object sender, EventArgs e)
    {
        Response.Write(ddl.SelectedValue + " " + Request["ddl"]);
        Response.End();
    }
    //為了讓Cient新增的DropDownList選項被接受,Page需覆寫Render方法
    //註冊前端可能動態加入的新選項
    protected override void Render(HtmlTextWriter writer)
    {
        ClientScript.RegisterForEventValidation(
            ddl.UniqueID, "JavaScript");
        base.Render(writer);
    }
 
</script>
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Test DropDownList Change in Client Side</title>
    <script src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.0.min.js"></script>
    <script >
        $(function () {
            //動態增加兩個新選項,注意: 選Ruby送出會出錯,選JavaScript卻OK
            $("#ddl")
            .append("<option value='Ruby' selected>Ruby</option>")
            .append("<option value='JavaScript'>JavaScript</option>");
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <asp:DropDownList ID="ddl" runat="server">
            <asp:ListItem>C#</asp:ListItem>
            <asp:ListItem>VB.NET</asp:ListItem>
        </asp:DropDownList>
        <asp:Button ID="btn" runat="server" OnClick="btn_Click" Text="Submit" />
    </form>
</body>
</html>

執行結果如上圖,下拉選單會出現四個選項,選Ruby按Submit會出錯(如下圖);選C#、VB.NET、JavaScript按Submit則不會出錯。

但是還有一個問題: 選取JavaScript雖然不會出錯,Request["ddl"]也能取得選取結果--"JavaScript",但透過ddl.SelectedValue查到的卻是C#,表示DropDownList.Selected*屬性只接受Server端建立的選項,應用時需留意此一限制。

如此看來,若只是為了在Server端及Client端都能增減下拉選單選項,可以不用DropDownList,改用<select runat="server">更簡單,且後端取值應以Request["…"]為準。

<%@ Page Language="C#" %>
 
<!DOCTYPE html>
 
<script runat="server">
    protected void btn_Click(object sender, EventArgs e)
    {
        Response.Write(Request["ddl"]);
        Response.End();
    }
</script>
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Test DropDownList Change in Client Side</title>
    <script src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.0.min.js"></script>
    <script >
        $(function () {
            //動態增加兩個新選項
            $("#ddl")
            .append("<option value='Ruby' selected>Ruby</option>")
            .append("<option value='JavaScript'>JavaScript</option>");
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <select name="ddl" id="ddl" runat="server">
            <option>C#</option>
            <option>VB.NET</option>
        </select>
        <asp:Button ID="btn" runat="server" OnClick="btn_Click" Text="Submit" />
    </form>
</body>
</html>
歡迎推文分享:
Published 07 June 2013 11:15 PM 由 Jeffrey
Filed under:



意見

# 羽落 said on 11 June, 2013 04:38 AM

但如此一來,資料的安全性及正確性就必須要在後端確認了,對嗎?

# Jeffrey said on 11 June, 2013 09:27 AM

to 羽落,無論前端加了多少層檢核防護,後端一定要再檢核驗證一次。前端驗證只能用於改善無效資料送回後端才被拒絕的無效率,無法阻擋惡意破解及篡改,如資訊安全及資料正確事關重大,真正的關卡只能設在後端。

# 羽落 said on 12 June, 2013 10:34 PM

是的,我了解,謝謝Jeffrey大。

# 老皮 said on 29 July, 2013 12:21 PM

請問一下大大,若是在WebFrom的控制項中我想要多設定一些相關的資訊,有沒有類似在WinForm中有Tag的屬性可以讓我暫時設定相關的資料?或是說有什麼方式可以存放控制項的相關資訊?謝謝

# Jeffrey said on 29 July, 2013 08:28 PM

to 老皮, 我想到較相近的機制是ViewState(參考: www.dotblogs.com.tw/.../25923.aspx),它是全Page共用,不像Tag依附在特定Control,但可透過Key/Value概念管理。但要留意,ViewState會被編碼後成為網頁的一部分反覆傳送,要避免放入大型資料拖累傳輸效能。

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<June 2013>
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456
 
RSS
【工商服務】
OrcsWeb: Windows Server Hosting
twMVC
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication