首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET Web Forms 控制項 vs 母版頁面深度解析:CodeBehind 模式、驗證控制項、檔案上傳、母版頁面穿透式存取與路徑解析

     編輯:ASP.NET 基礎

一、CodeBehind 架構與頁面生命週期

  • .aspx:宣告式標記 (控制項樹、HTML、CSS)、`Inherits="Namespace.Class"` 指向後端類別。
  • .aspx.cs:`partial class PageName : System.Web.UI.Page`,`protected` 欄位自動對應 ``。
  • **存取層級**:後端類別為頁面類別的**子類別** (透過動態編譯繼承),因此 `.aspx` 內 `<% %>` 程式碼塊與控制項事件處理函式,**必須是 `protected` 或 `public`**,`private` 會導致編譯錯誤 (CS0122)。

二、常用伺服器控制項進階用法

Literal — XSS 防護關鍵

<asp:Literal ID="litContent" runat="server" Mode="Encode" />

TextBox — AutoPostBack 即時驗證

<asp:TextBox ID="txtEmail" runat="server" AutoPostBack="true" OnTextChanged="txtEmail_TextChanged" />

Button — OnClientClick 客戶端確認

<asp:Button ID="btnDelete" runat="server" Text="刪除" 
    OnClientClick="return confirm('確定刪除?');" 
    OnClick="btnDelete_Click" />

CommandName/CommandArgument — 多按鈕共用事件

<asp:Button ID="btnEdit" runat="server" CommandName="Edit" CommandArgument='<%# Eval("ID") %>' OnCommand="btn_Command" />
<asp:Button ID="btnDel" runat="server" CommandName="Delete" CommandArgument='<%# Eval("ID") %>' OnCommand="btn_Command" />

protected void btn_Command(object sender, CommandEventArgs e)
{
    int id = Convert.ToInt32(e.CommandArgument);
    if (e.CommandName == "Edit") Response.Redirect($"Edit.aspx?id={id}");
    else if (e.CommandName == "Delete") DeleteRecord(id);
}

Panel — GroupingText 渲染為 Fieldset

<asp:Panel ID="pnlAdvanced" runat="server" GroupingText="進階設定" DefaultButton="btnSearch">
    <!-- 內容 -->
</asp:Panel>

HyperLink — 虛擬路徑自動解析

<asp:HyperLink ID="hlHome" runat="server" NavigateUrl="~/Default.aspx" Text="首頁" />

FileUpload — 完整上傳流程與安全

protected void btnUpload_Click(object sender, EventArgs e)
{
    if (!fuPhoto.HasFile) { ShowMsg("請選擇檔案"); return; }

    // 1. 副檔名白名單
    string ext = System.IO.Path.GetExtension(fuPhoto.FileName).ToLower();
    string[] allow = { ".jpg", ".jpeg", ".png", ".gif", ".pdf" };
    if (!allow.Contains(ext)) { ShowMsg("副檔名不允許"); return; }

    // 2. 檔案大小限制 (web.config httpRuntime maxRequestLength 亦需設定)
    if (fuPhoto.PostedFile.ContentLength > 2 * 1024 * 1024) { ShowMsg("超過 2MB"); return; }

    // 3. 安全儲存:隨機檔名 + 非網頁執行目錄
    string saveDir = Server.MapPath("~/App_Data/Uploads/");
    if (!System.IO.Directory.Exists(saveDir)) System.IO.Directory.CreateDirectory(saveDir);
    string saveName = Guid.NewGuid().ToString("N") + ext;
    fuPhoto.SaveAs(System.IO.Path.Combine(saveDir, saveName));

    // 4. 記錄資料庫...
    ShowMsg("上傳成功");
}
⚠️ **漏洞防護**:上傳目錄**禁用執行權限** (IIS 處理常式對應移除 .aspx/.ashx/.php),檔名**隨機化**,副檔名**白名單**,儲存於 **App_Data 或網站根目錄外**。

三、驗證控制項完整體系

控制項用途關鍵屬性
RequiredFieldValidator必填`ControlToValidate`, `InitialValue` (下拉預設值), `ErrorMessage`/`Text`
RangeValidator範圍 (數字/日期/字串)`Type`, `MinimumValue`, `MaximumValue`
CompareValidator比較 (兩欄位相等/大小/型別)`ControlToCompare`, `Operator`, `Type`
RegularExpressionValidator正則驗證 (Email/電話/身分證)`ValidationExpression`
CustomValidator自訂邏輯`OnServerValidate` (後端), `ClientValidationFunction` (前端 JS)
ValidationSummary錯誤摘要顯示`ShowMessageBox`, `ShowSummary`, `HeaderText`

共同核心機制

  • `ValidationGroup`:分組驗證,按鈕同組才觸發該組驗證 (單頁多表單)。
  • `CausesValidation`:控制項是否觸發驗證 (預設 `true`,取消按鈕設 `false`)。
  • **伺服器端必檢**:`if (!Page.IsValid) return;` — **防止繞過客戶端驗證** (JS 停用/攔截)。
  • `Text` vs `ErrorMessage`:`Text` 顯示於驗證控制項位置 (通常 `*`),`ErrorMessage` 顯示於 `ValidationSummary`。

CustomValidator 範例:伺服器端檢查帳號唯一

<asp:CustomValidator ID="cvUser" runat="server" ControlToValidate="txtUser" 
    OnServerValidate="cvUser_ServerValidate" ErrorMessage="帳號已存在" />

protected void cvUser_ServerValidate(object source, ServerValidateEventArgs args)
{
    args.IsValid = !UserBLL.Exists(args.Value); // false = 驗證失敗
}

四、母版頁面 — 版面共用與穿透式存取

基本結構

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="WebApp.SiteMaster" %>
<html><body>
    <header><asp:ContentPlaceHolder ID="head" runat="server" /></header>
    <nav><asp:LinkButton ID="lnkLogout" runat="server" OnClick="lnkLogout_Click" /></nav>
    <main><asp:ContentPlaceHolder ID="MainContent" runat="server" /></main>
    <footer>© 2024</footer>
</body></html>

內容頁面

<%@ Page Language="C#" MasterPageFile="~/Site.master" CodeBehind="Default.aspx.cs" Inherits="WebApp.Default" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <h1>首頁內容</h1>
</asp:Content>

內容頁存取母版控制項/屬性/方法

// 1. FindControl (弱型別)
Button btn = (Button)Master.FindControl("lnkLogout");
if (btn != null) btn.Visible = false;

// 2. 強型別 (需 @MasterType 指令)
<%@ MasterType VirtualPath="~/Site.master" %>
// 之後可直接 this.Master.LnkLogout.Visible = false;
// 前提:母版頁面公開 public 屬性/方法
public LinkButton LnkLogout => lnkLogout;
public void SetNavActive(string navId) { /* 邏輯 */ }

母版頁面存取內容頁控制項 (較少見)

ContentPlaceHolder cp = (ContentPlaceHolder)FindControl("MainContent");
if (cp != null)
{
    TextBox txt = (TextBox)cp.FindControl("txtSearch");
    // ...
}

五、虛擬路徑解析:ResolveUrl vs ResolveClientUrl

方法行為適用場景
Page.ResolveUrl("~/Images/x.jpg")回傳 **根相對路徑** `/AppName/Images/x.jpg`伺服器端控制項屬性、CSS `url()`、一般情況
Page.ResolveClientUrl("~/Images/x.jpg")回傳 **相對目前頁面** 的路徑 `../Images/x.jpg` 或 `Images/x.jpg`客戶端 ``、``、JS 動態產生 URL
VirtualPathUtility.ToAbsolute("~/Images/x.jpg")同 `ResolveUrl`,無需 Page 實例非頁面類別 (Helper、BLL、Handler)

母版頁面中路徑解析陷阱

  • 母版與內容頁**目錄層級不同**時,`` 在母版 `` 中**不會**自動解析 (非伺服器控制項)。
  • 解法:`` 或改用 ``。

六、註冊頁面完整範例 (Register.aspx/.cs) — 整合驗證、jQuery 客戶端強度檢查、PRG 模式

<%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeBehind="Register.aspx.cs" Inherits="WebApp.Register" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <asp:ValidationSummary ID="vsMain" runat="server" CssClass="alert alert-danger" HeaderText="請修正下列錯誤:" />
    <table class="form-table">
        <tr>
            <td><asp:Label Text="帳號" AssociatedControlID="txtUser" /></td>
            <td>
                <asp:TextBox ID="txtUser" runat="server" AutoPostBack="true" OnTextChanged="txtUser_TextChanged" />
                <asp:RequiredFieldValidator ControlToValidate="txtUser" Text="*" ErrorMessage="帳號必填" />
                <asp:CustomValidator ID="cvUser" ControlToValidate="txtUser" OnServerValidate="cvUser_ServerValidate" Text="*" ErrorMessage="帳號已存在" />
                <asp:Label ID="lblUserMsg" runat="server" CssClass="text-danger" Visible="false" />
            </td>
        </tr>
        <tr>
            <td><asp:Label Text="密碼" AssociatedControlID="txtPwd" /></td>
            <td>
                <asp:TextBox ID="txtPwd" runat="server" TextMode="Password" />
                <asp:RequiredFieldValidator ControlToValidate="txtPwd" Text="*" ErrorMessage="密碼必填" />
                <span id="pwdStrength"></span> <!-- jQuery 即時強度 -->
            </td>
        </tr>
        <tr>
            <td><asp:Label Text="確認密碼" AssociatedControlID="txtPwd2" /></td>
            <td>
                <asp:TextBox ID="txtPwd2" runat="server" TextMode="Password" />
                <asp:CompareValidator ControlToValidate="txtPwd2" ControlToCompare="txtPwd" Operator="Equal" Text="*" ErrorMessage="兩次密碼不一致" />
            </td>
        </tr>
        <tr>
            <td><asp:Label Text="Email" AssociatedControlID="txtEmail" /></td>
            <td>
                <asp:TextBox ID="txtEmail" runat="server" />
                <asp:RegularExpressionValidator ControlToValidate="txtEmail" ValidationExpression="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" Text="*" ErrorMessage="Email 格式錯誤" />
            </td>
        </tr>
        <tr>
            <td></td><td><asp:Button ID="btnReg" Text="註冊" OnClick="btnReg_Click" /></td>
        </tr>
    </table>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="head" runat="server">
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
        $(function(){
            $('#<%=txtPwd.ClientID%>').on('blur', function(){
                var v = $(this).val();
                if (v.length < 6) $('#pwdStrength').text('弱').css('color','red');
                else if (/[a-z]/.test(v) && /[A-Z]/.test(v) && /[0-9]/.test(v)) $('#pwdStrength').text('強').css('color','green');
                else $('#pwdStrength').text('中').css('color','orange');
            });
        });
    </script>
</asp:Content>
protected void btnReg_Click(object sender, EventArgs e)
{
    if (!Page.IsValid) return; // 關鍵:伺服器端二次驗證

    // 密碼雜湊
    string hash = BCrypt.Net.BCrypt.HashPassword(txtPwd.Text); // NuGet: BCrypt.Net-Next

    long userId = UserBLL.Insert(txtUser.Text.Trim(), hash, txtEmail.Text.Trim());
    Session["UserId"] = userId;
    Session["Auth"] = true;

    // PRG 模式:Redirect 避免 F5 重複提交
    Response.Redirect("Target.aspx?msg=註冊成功&url=Default.aspx");
}

七、三種控制項類型比較

類型標記伺服器端可存取ViewState事件模型用途
HTML 控制項``是 (`HtmlInputText`)有有限舊專案遷移、精確控制輸出 HTML
Web Server 控制項``是 (豐富物件模型)完整完整**標準開發首選**
HTML 純標籤``否無無靜態內容、前端框架模板區塊

總結

  • **CodeBehind**:`protected` 欄位對應控制項,母版頁面 `@MasterType` 強型別存取。
  • **驗證控制項**:`ValidationGroup` 分組、`Page.IsValid` 伺服器端必檢、`CustomValidator` 彈性擴充。
  • **FileUpload**:白名單、大小限制、隨機檔名、非執行目錄、資料庫記錄。
  • **母版頁面**:版面共用、`ContentPlaceHolder` 注入、`FindControl`/`@MasterType` 雙向存取。
  • **路徑解析**:`ResolveUrl` (根相對) vs `ResolveClientUrl` (相對目前頁),母版頁面非伺服器標籤必須手動解析。
  • **現代化建議**:新專案考慮 **ASP.NET Core Razor Pages / Blazor**,標記與邏輯更分離、支援 Dependency Injection、Tag Helpers 取代 Server Controls、原生支援現代前端工具鏈。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved