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

ASP.NET 基礎頁面架構設計:BasePage 繼承體系與跨頁面共用邏輯實戰

     編輯:關於ASP.NET

為什麼需要 BasePage?

ASP.NET WebForms 雖支援繼承,但無法像 WinForms 那樣進行視覺化介面繼承。為解決跨頁面共同需求(權限檢查、日誌、URL 重寫、共用屬性/方法),採用 BasePage 繼承鏈 是經典最佳實踐。

分層繼承架構設計

System.Web.UI.Page
    │
    ▼
BasePage (根基類)          → 無業務邏輯:URL Rewrite、全域例外處理、Log4Net、多語系初始化
    │
    ▼
BizBasePage (業務基類)     → 業務共用屬性:CurrentUser、CurrentTenant、PermissionService、DbContext
    │
    ├──────────────────┬──────────────────┐
    ▼                  ▼                  ▼
ViewBasePage       EditBasePage       ListBasePage
(檢視頁)            (編輯頁)            (列表/查詢頁)

各層職責詳細定義

層級核心職責典型成員
BasePage基礎設施、橫切關注點OnError、OnPreInit、RewriteUrl、WriteLog、SetCulture
BizBasePage業務上下文、權限、資料存取CurrentUserId、TenantId、HasPermission(string)、UnitOfWork
ViewBasePage唯讀顯示、資料繫結BindDetail(int id)、SetReadOnlyMode()
EditBasePage新增/編輯、驗證、儲存SaveEntity()、ValidateInput()、RedirectAfterSave()
ListBasePage分頁、排序、篩選、匯出GridView、PageSize、SortExpression、ExportToExcel()

實作範例:查詢基類頁

public abstract class QueryBasePage : BizBasePage {
    protected abstract IDataAccess DataAccess { get; }
    protected abstract string DefaultSortColumn { get; }
    protected abstract Control GridControl { get; }

    protected void BindGrid(string whereClause, string sortExpr) {
        var dt = DataAccess.GetPagedData(whereClause, sortExpr, CurrentPageIndex, PageSize);
        ((BaseDataBoundControl)GridControl).DataSource = dt;
        ((BaseDataBoundControl)GridControl).DataBind();
        UpdatePager(dt.Rows.Count);
    }

    protected virtual void btnQuery_Click(object sender, EventArgs e) {
        string where = BuildWhereClause(); // 子類實作
        BindGrid(where, DefaultSortColumn);
    }
}

// 具體頁面
public class UserQueryPage : QueryBasePage {
    protected override IDataAccess DataAccess => new UserRepository();
    protected override string DefaultSortColumn => "CreateDate DESC";
    protected override Control GridControl => gvUsers;

    protected override string BuildWhereClause() {
        var sb = new StringBuilder("1=1");
        if (!string.IsNullOrEmpty(txtName.Text)) sb.Append($" AND Name LIKE '%{txtName.Text}%'");
        if (!string.IsNullOrEmpty(txtEmail.Text)) sb.Append($" AND Email LIKE '%{txtEmail.Text}%'");
        return sb.ToString();
    }
}

進階技巧:Filter 屬性與 Model Binder 整合

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class RequirePermissionAttribute : Attribute {
    public string PermissionCode { get; set; }
}

public class BasePage : Page {
    protected override void OnInit(EventArgs e) {
        var attr = GetType().GetCustomAttribute();
        if (attr != null && !CurrentUser.HasPermission(attr.PermissionCode)) {
            Response.Redirect("~/AccessDenied.aspx");
        }
        base.OnInit(e);
    }
}

// 使用
[RequirePermission(PermissionCode = "USER_VIEW")]
public class UserListPage : ListBasePage { ... }

常見陷阱與解決方案

  • ViewState 衝突:基類與子類同名控制項 ID 導致 ViewState 錯誤 → 規範命名慣例(基類控制項前綴 base_)。
  • 事件綁定順序:基類 Page_Load 早於子類 → 使用 OnLoad 覆寫而非事件訂閱,或明確呼叫 base.OnLoad(e)。
  • 測試困難:強耦合 HttpContext → 引入介面 IHttpContextWrapper,單元測試時注入 Mock。
  • 過度繼承:超過 4 層繼承難以維護 → 改用組合模式(BasePage 注入 IAuthService、ILogService 等服務)。

遷移至 ASP.NET Core Razor Pages / MVC

Core 採用 Filter Pipeline(AuthorizationFilter、ActionFilter、ResultFilter、ExceptionFilter)取代 BasePage 繼承,配合 Dependency Injection 注入共用服務,Tag Helpers / ViewComponents 實現 UI 重用,架構更彈性、可測試。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved