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

ASP.NET 2.0 資料操作:建立業務邏輯層 (BLL) 完整教學

     編輯:關於ASP.NET

為什麼需要 BLL?

資料存取層 (DAL) 只負責「如何存取資料」,不包含「業務規則」。業務邏輯層 (BLL) 位於表示層與 DAL 之間,封裝驗證、授權、工作流程、跨表一致性等規則,確保資料操作符合業務需求,並提供乾淨、可測試的 API 給表示層呼叫。

分層架構圖

表示層
    │  呼叫 BLL 方法、繫結 ObjectDataSource
    ▼
業務邏輯層 (BLL)  ←─ 驗證規則、授權、稽核、交易協調
    │  呼叫 DAL 方法
    ▼
資料存取層 (DAL)  ←─ SQL/預存程序、連線管理、資料對應
    │
    ▼
資料庫

建立 BLL 步驟實戰

1. 專案結構組織

  • 方案總管 → App_Code → 新增資料夾 DAL、BLL。
  • 將現有 Typed DataSet (.xsd) 移入 DAL。
  • 在 BLL 建立類別檔:ProductsBLL.cs、CategoriesBLL.cs、SuppliersBLL.cs、EmployeesBLL.cs。

2. ProductsBLL 核心實作

using System;
using System.Data;
using DAL; // 命名空間對應資料夾

namespace BLL
{
    [System.ComponentModel.DataObject] // 支援 ObjectDataSource 設計時偵測
    public class ProductsBLL
    {
        private ProductsTableAdapter _adapter = new ProductsTableAdapter();

        [System.ComponentModel.DataObjectMethod(DataObjectMethodType.Select, true)]
        public Northwind.ProductsDataTable GetProducts()
        {
            return _adapter.GetProducts();
        }

        [System.ComponentModel.DataObjectMethod(DataObjectMethodType.Select, false)]
        public Northwind.ProductsDataTable GetProductsByCategory(int categoryID)
        {
            return _adapter.GetProductsByCategory(categoryID);
        }

        [System.ComponentModel.DataObjectMethod(DataObjectMethodType.Insert, true)]
        public int InsertProduct(string productName, int? supplierID, int? categoryID,
            string quantityPerUnit, decimal? unitPrice, short? unitsInStock,
            short? unitsOnOrder, short? reorderLevel, bool discontinued)
        {
            // 業務規則驗證
            if (string.IsNullOrWhiteSpace(productName))
                throw new ArgumentException("產品名稱不可空白");
            if (unitPrice.HasValue && unitPrice < 0)
                throw new ArgumentException("單價不可為負數");
            if (unitsInStock.HasValue && unitsInStock < 0)
                throw new ArgumentException("庫存不可為負數");

            // 呼叫 DAL 執行新增
            return _adapter.Insert(productName, supplierID, categoryID,
                quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder,
                reorderLevel, discontinued);
        }

        [System.ComponentModel.DataObjectMethod(DataObjectMethodType.Update, true)]
        public bool UpdateProduct(string productName, int? supplierID, int? categoryID,
            string quantityPerUnit, decimal? unitPrice, short? unitsInStock,
            short? unitsOnOrder, short? reorderLevel, bool discontinued,
            int productID)
        {
            // 業務規則:停售產品不可修改供應商/分類
            Northwind.ProductsRow row = _adapter.GetProductByID(productID)[0];
            if (row.Discontinued && (supplierID != row.SupplierID || categoryID != row.CategoryID))
                throw new InvalidOperationException("停售產品不得變更供應商或分類");

            int affected = _adapter.Update(productName, supplierID, categoryID,
                quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder,
                reorderLevel, discontinued, productID);
            return affected == 1;
        }

        [System.ComponentModel.DataObjectMethod(DataObjectMethodType.Delete, true)]
        public bool DeleteProduct(int productID)
        {
            // 授權檢查:僅管理員可刪除
            if (!HttpContext.Current.User.IsInRole("Administrators"))
                throw new UnauthorizedAccessException("僅管理員可刪除產品");

            int affected = _adapter.Delete(productID);
            return affected == 1;
        }
    }
}

3. ObjectDataSource 繫結 BLL

<asp:ObjectDataSource ID="odsProducts" runat="server"
    TypeName="BLL.ProductsBLL"
    SelectMethod="GetProducts"
    InsertMethod="InsertProduct"
    UpdateMethod="UpdateProduct"
    DeleteMethod="DeleteProduct"
    DataObjectTypeName="DAL.Northwind.ProductsRow" >
</asp:ObjectDataSource>

DataObjectTypeName 指定強型別資料列,ObjectDataSource 自動將表單欄位對應至 ProductsRow 屬性,傳遞給 BLL 方法,免去逐一宣告參數。

進階主題

交易處理

跨多個 DAL 更新需保持原子性:

using (TransactionScope scope = new TransactionScope())
{
    _adapter.Update(...);
    _otherAdapter.Update(...);
    scope.Complete();
}

快取策略

  • BLL 方法加上 [DataObjectMethod(DataObjectMethodType.Select, true)] 標記預設查詢。
  • ObjectDataSource EnableCaching="true" CacheDuration="300" 快取查詢結果。
  • 搭配 SqlCacheDependency 實現資料異動自動失效。

單元測試友善設計

  • BLL 建構子注入 DAL 介面:public ProductsBLL(IProductsDAL dal)。
  • 測試時傳入 Mock DAL,驗證業務規則邏輯無需真實資料庫。

例外處理與使用者回饋

protected void odsProducts_Inserted(object sender, ObjectDataSourceStatusEventArgs e)
{
    if (e.Exception != null)
    {
        lblError.Text = "新增失敗:" + e.Exception.GetBaseException().Message;
        e.ExceptionHandled = true; // 防止黃色死機畫面
    }
}

BLL 設計最佳實務檢核表

  • [ ] 每個公用方法對應單一業務用例,命名語意清晰(GetProductsByCategory 而非 GetData)。
  • [ ] 所有輸入參數在進入 DAL 前完成驗證、轉換、清理。
  • [ ] 業務規則集中於 BLL,DAL 純粹執行 CRUD。
  • [ ] 使用 DataObjectAttribute、DataObjectMethodAttribute 豐富設計時中繼資料。
  • [ ] 敏感操作(刪除、批次更新)實作授權檢查。
  • [ ] 記錄稽核日誌(誰、何時、做什麼、前後值)。
  • [ ] 方法回傳型別明確:bool 表示成敗、int 回傳新 ID、Entity 回傳完整物件。

結語

建立業務邏輯層 (BLL) 是 ASP.NET 2.0 邁向專業分層架構的關鍵步驟。它將「業務規則」從頁面程式碼與資料存取中剝離,形成可重用、可測試、可維護的核心資產。配合 ObjectDataSource、DataObjectTypeName、TransactionScope、單元測試注入等技術,即可打造企業級資料驅動應用的堅實骨幹。

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