创建业务逻辑层 (VB)

作者 :Scott Mitchell

下载 PDF

本教程介绍如何将业务规则集中到业务逻辑层 (BLL) 中,该层充当表示层和 DAL 之间数据交换的中介。

简介

在第一个教程中创建的数据访问层 (DAL) 将数据访问逻辑与呈现逻辑完全分离。 但是,虽然 DAL 将数据访问详细信息与表示层完全分离,但它不强制实施任何可能适用的业务规则。 例如,对于我们的应用程序,我们可能希望禁止CategoryID在字段设置为 1 时Discontinued修改表的 ProductsSupplierID 字段,或者我们可能希望强制实施资历规则,从而禁止员工由其后雇用的人员管理的情况。 另一种常见方案是授权,也许只有具有特定角色的用户才能删除产品或更改 UnitPrice 值。

本教程介绍如何将这些业务规则集中到业务逻辑层 (BLL) 中,该层充当表示层和 DAL 之间的数据交换的中介。 在实际应用程序中,BLL 应作为单独的类库项目实现;但是,对于这些教程,我们将实现 BLL 作为文件夹中的一系列类 App_Code ,以简化项目结构。 图 1 说明了表示层、BLL 和 DAL 之间的体系结构关系。

BLL 将表示层与数据访问层分开并施加业务规则

图 1:BLL 将表示层与数据访问层分开,并强制实施业务规则

我们不是创建单独的类来实现 我们的业务逻辑,而是直接将此逻辑放在具有分部类的类型化数据集中。 有关创建和扩展类型化数据集的示例,请参阅第一个教程。

步骤 1:创建 BLL 类

我们的 BLL 将由四个类组成,DAL 中的每个 TableAdapter 各对应一个类:其中每个 BLL 类都有用于从 DAL 中相应的 TableAdapter 中检索、插入、更新和删除的方法,并应用相应的业务规则。

为了更清晰地分隔与 DAL 和 BLL 相关的类,让我们在 App_Code 文件夹中创建两个子文件夹, DALBLL。 只需右键单击App_Code解决方案资源管理器中的文件夹,然后选择“新建文件夹”。 创建这两个文件夹后,将第一个教程中创建的类型化数据集移动到 DAL 子文件夹中。

接下来,在子文件夹中创建四个 BLL BLL 类文件。 为此,请 BLL 右键单击子文件夹,选择“添加新项”,然后选择“类”模板。 将四个类命名为 ProductsBLLCategoriesBLLSuppliersBLLEmployeesBLL

将四个新类添加到 App_Code 文件夹

图 2:向 文件夹添加四个新类App_Code

接下来,让我们向每个类添加方法,以包装第一个教程中为 TableAdapters 定义的方法。 目前,这些方法将直接调用 DAL;稍后将返回以添加任何所需的业务逻辑。

注意

如果使用 Visual Studio Standard Edition 或更高版本 (即使用 Visual Web Developer) ,则可以选择使用类Designer直观地设计类。 有关 Visual Studio 中此新功能的详细信息,请参阅类Designer博客

对于 类, ProductsBLL 需要总共添加七个方法:

  • GetProducts() 返回所有产品
  • GetProductByProductID(productID) 返回具有指定产品 ID 的产品
  • GetProductsByCategoryID(categoryID) 返回指定类别中的所有产品
  • GetProductsBySupplier(supplierID) 返回来自指定供应商的所有产品
  • AddProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued) 使用传入的值将新产品插入数据库;返回 ProductID 新插入的记录的值
  • UpdateProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued, productID) 使用传入值更新数据库中的现有产品; True 如果仅更新了一行,则返回 ; False 否则返回
  • DeleteProduct(productID) 从数据库中删除指定的产品

ProductsBLL.vb

Imports NorthwindTableAdapters

<System.ComponentModel.DataObject()> _
Public Class ProductsBLL

    Private _productsAdapter As ProductsTableAdapter = Nothing
    Protected ReadOnly Property Adapter() As ProductsTableAdapter
        Get
            If _productsAdapter Is Nothing Then
                _productsAdapter = New ProductsTableAdapter()
            End If

            Return _productsAdapter
        End Get
    End Property

    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Select, True)> _
    Public Function GetProducts() As Northwind.ProductsDataTable
        Return Adapter.GetProducts()
    End Function

    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Select, False)> _
    Public Function GetProductByProductID(ByVal productID As Integer) _
        As Northwind.ProductsDataTable
        Return Adapter.GetProductByProductID(productID)
    End Function

    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Select, False)> _
    Public Function GetProductsByCategoryID(ByVal categoryID As Integer) _
        As Northwind.ProductsDataTable
        Return Adapter.GetProductsByCategoryID(categoryID)
    End Function

    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Select, False)> _
    Public Function GetProductsBySupplierID(ByVal supplierID As Integer) _
        As Northwind.ProductsDataTable
        Return Adapter.GetProductsBySupplierID(supplierID)
    End Function

    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Insert, True)> _
    Public Function AddProduct( _
        productName As String, supplierID As Nullable(Of Integer), _
        categoryID As Nullable(Of Integer), quantityPerUnit As String, _
        unitPrice As Nullable(Of Decimal), unitsInStock As Nullable(Of Short), _
        unitsOnOrder As Nullable(Of Short), reorderLevel As Nullable(Of Short), _
        discontinued As Boolean) _
        As Boolean

        Dim products As New Northwind.ProductsDataTable()
        Dim product As Northwind.ProductsRow = products.NewProductsRow()

        product.ProductName = productName
        If Not supplierID.HasValue Then
            product.SetSupplierIDNull()
        Else
            product.SupplierID = supplierID.Value
        End If

        If Not categoryID.HasValue Then
            product.SetCategoryIDNull()
        Else
            product.CategoryID = categoryID.Value
        End If

        If quantityPerUnit Is Nothing Then
            product.SetQuantityPerUnitNull()
        Else
            product.QuantityPerUnit = quantityPerUnit
        End If

        If Not unitPrice.HasValue Then
            product.SetUnitPriceNull()
        Else
            product.UnitPrice = unitPrice.Value
        End If

        If Not unitsInStock.HasValue Then
            product.SetUnitsInStockNull()
        Else
            product.UnitsInStock = unitsInStock.Value
        End If

        If Not unitsOnOrder.HasValue Then
            product.SetUnitsOnOrderNull()
        Else
            product.UnitsOnOrder = unitsOnOrder.Value
        End If

        If Not reorderLevel.HasValue Then
            product.SetReorderLevelNull()
        Else
            product.ReorderLevel = reorderLevel.Value
        End If

        product.Discontinued = discontinued

        products.AddProductsRow(product)
        Dim rowsAffected As Integer = Adapter.Update(products)

        Return rowsAffected = 1
    End Function

    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Update, True)> _
    Public Function UpdateProduct(_
        productName As String, supplierID As Nullable(Of Integer), _
        categoryID As Nullable(Of Integer), quantityPerUnit As String, _
        unitPrice As Nullable(Of Decimal), unitsInStock As Nullable(Of Short), _
        unitsOnOrder As Nullable(Of Short), reorderLevel As Nullable(Of Short), _
        discontinued As Boolean, productID As Integer) _
        As Boolean

        Dim products As Northwind.ProductsDataTable = _
            Adapter.GetProductByProductID(productID)

        If products.Count = 0 Then
            Return False
        End If

        Dim product as Northwind.ProductsRow = products(0)

        product.ProductName = productName
        If Not supplierID.HasValue Then
            product.SetSupplierIDNull()
        Else
            product.SupplierID = supplierID.Value
        End If

        If Not categoryID.HasValue Then
            product.SetCategoryIDNull()
        Else
            product.CategoryID = categoryID.Value
        End If

        If quantityPerUnit Is Nothing Then
            product.SetQuantityPerUnitNull()
        Else
            product.QuantityPerUnit = quantityPerUnit
        End If

        If Not unitPrice.HasValue Then
            product.SetUnitPriceNull()
        Else
            product.UnitPrice = unitPrice.Value
        End If

        If Not unitsInStock.HasValue Then
            product.SetUnitsInStockNull()
        Else
            product.UnitsInStock = unitsInStock.Value
        End If

        If Not unitsOnOrder.HasValue Then
            product.SetUnitsOnOrderNull()
        Else
            product.UnitsOnOrder = unitsOnOrder.Value
        End If

        If Not reorderLevel.HasValue Then
            product.SetReorderLevelNull()
        Else
            product.ReorderLevel = reorderLevel.Value
        End If

        product.Discontinued = discontinued

        Dim rowsAffected As Integer = Adapter.Update(product)

        Return rowsAffected = 1
    End Function

    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Delete, True)> _
    Public Function DeleteProduct(ByVal productID As Integer) As Boolean
        Dim rowsAffected As Integer = Adapter.Delete(productID)

        Return rowsAffected = 1
    End Function
End Class

仅返回数据 GetProducts、、 GetProductByProductIDGetProductsByCategoryIDGetProductBySuppliersID 的方法非常简单,因为它们只需向下调用 DAL。 虽然在某些情况下,可能需要在此级别实现业务规则 (例如基于当前登录用户或用户所属角色) 授权规则,但我们只是将这些方法保留原样。 对于这些方法,BLL 仅充当代理,表示层通过该代理从数据访问层访问基础数据。

AddProductUpdateProduct 方法都作为参数采用各种产品字段的值,并分别添加新产品或更新现有产品。 由于表的许多 Product 列可以接受 NULL (CategoryIDSupplierIDUnitPrice的值(例如几个) ),因此,对于 AddProductUpdateProduct 映射到此类列的输入参数使用 可为 null 的类型。 可以为 Null 的类型是 .NET 2.0 的新增功能,它提供一种技术来指示值类型是否应改为 Nothing。 有关详细信息,请参阅 Paul Vick 的博客文章 “关于 Nullable 类型和 VB 的真相”“可为 Null” 结构的技术文档。

这三种方法都返回一个布尔值,指示是插入、更新或删除了行,因为该操作不会导致受影响的行。 例如,如果页面开发人员为不存在的产品调用DeleteProduct传入 的 ,DELETE则颁发给数据库的语句将没有任何影响,因此该方法DeleteProduct将返回 FalseProductID

请注意,在添加新产品或更新现有产品时,我们将新产品或修改后的产品的字段值作为标量列表,而不是接受 ProductsRow 实例。 之所以选择此方法, ProductsRow 是因为 类派生自 ADO.NET DataRow 类,该类没有默认的无参数构造函数。 为了创建新ProductsRow实例,必须首先创建一个ProductsDataTable实例,然后调用其NewProductRow()方法 (我们在) 中执行。AddProduct 当我们转向使用 ObjectDataSource 插入和更新产品时,这一缺点会回过头来。 简言之,ObjectDataSource 将尝试创建输入参数的实例。 如果 BLL 方法需要实例 ProductsRow ,则 ObjectDataSource 将尝试创建一个实例,但由于缺少默认无参数构造函数而失败。 有关此问题的详细信息,请参阅以下两篇 ASP.NET 论坛文章: 使用 Strongly-Typed 数据集更新 ObjectDataSourcesObjectDataSource 和 Strongly-Typed DataSet 的问题。

接下来,在 和 UpdateProductAddProduct,代码将创建一个ProductsRow实例,并使用刚刚传入的值填充该实例。 向 DataRow 的 DataColumns 分配值时,可能会进行各种字段级验证检查。 因此,手动将传入的值放回 DataRow 有助于确保将数据传递到 BLL 方法的有效性。 遗憾的是,Visual Studio 生成的强类型 DataRow 类不使用可为空的类型。 相反,为了指示 DataRow 中的特定 DataColumn 应对应于数据库值,NULLSetColumnNameNull()必须使用 方法。

在 中 UpdateProduct ,我们首先在产品中加载,以使用 GetProductByProductID(productID)进行更新。 虽然这似乎是不必要的数据库行程,但在探索乐观并发的未来教程中,此额外行程将被证明是有价值的。 乐观并发是一种技术,可确保同时处理相同数据的两个用户不会意外地覆盖彼此的更改。 抓取整个记录还可以更轻松地在 BLL 中创建仅修改 DataRow 列子集的更新方法。 浏览 类时, SuppliersBLL 我们将看到这样的示例。

最后,请注意 ProductsBLL ,类应用了 DataObject 属性[System.ComponentModel.DataObject] (语法紧邻文件顶部的类语句) 并且方法具有 DataObjectMethodAttribute 属性。 特性 DataObject 将类标记为适合绑定到 ObjectDataSource 控件的对象,而 DataObjectMethodAttribute 指示方法的用途。 正如我们在将来的教程中看到的那样,ASP.NET 2.0 的 ObjectDataSource 可以轻松地以声明方式访问类中的数据。 为了帮助筛选在 ObjectDataSource 的向导中要绑定到的可能类的列表,默认情况下,向导的下拉列表中仅显示标记为 DataObjects 的类。 类 ProductsBLL 在不使用这些属性的情况下同样工作,但添加它们可以更轻松地在 ObjectDataSource 的向导中使用。

添加其他类

ProductsBLL 完成后,我们仍需要添加类,以便与类别、供应商和员工合作。 请花点时间使用上述示例中的概念创建以下类和方法:

  • CategoriesBLL.cs

    • GetCategories()
    • GetCategoryByCategoryID(categoryID)
  • SuppliersBLL.cs

    • GetSuppliers()
    • GetSupplierBySupplierID(supplierID)
    • GetSuppliersByCountry(country)
    • UpdateSupplierAddress(supplierID, address, city, country)
  • EmployeesBLL.cs

    • GetEmployees()
    • GetEmployeeByEmployeeID(employeeID)
    • GetEmployeesByManager(managerID)

值得注意的一种方法是 SuppliersBLL 类的 UpdateSupplierAddress 方法。 此方法提供一个接口,用于仅更新供应商的地址信息。 在内部,此方法使用 GetSupplierBySupplierID) 在 对象中SupplierDataRow读取指定 supplierID (,设置其与地址相关的属性,然后向下SupplierDataTable调用 的 Update 方法。 方法 UpdateSupplierAddress 如下:

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateSupplierAddress(ByVal supplierID As Integer, _
    ByVal address As String, ByVal city As String, ByVal country As String) _
    As Boolean

    Dim suppliers As Northwind.SuppliersDataTable = _
        Adapter.GetSupplierBySupplierID(supplierID)

    If suppliers.Count = 0 Then
        Return False
    Else
        Dim supplier As Northwind.SuppliersRow = suppliers(0)

        If address Is Nothing Then
            supplier.SetAddressNull()
        Else
            supplier.Address = address
        End If

        If city Is Nothing Then
            supplier.SetCityNull()
        Else
            supplier.City = city
        End If

        If country Is Nothing Then
            supplier.SetCountryNull()
        Else
            supplier.Country = country
        End If

        Dim rowsAffected As Integer = Adapter.Update(supplier)

        Return rowsAffected = 1
    End If
End Function

有关 BLL 类的完整实现,请参阅本文的下载。

步骤 2:通过 BLL 类访问类型化数据集

在第一个教程中,我们看到了以编程方式直接使用类型化数据集的示例,但添加 BLL 类后,表示层应改为针对 BLL 工作。 在第 AllProducts.aspx 一个教程的示例中, ProductsTableAdapter 使用 将产品列表绑定到 GridView,如以下代码所示:

Dim productsAdapter As New ProductsTableAdapter()
GridView1.DataSource = productsAdapter.GetProducts()
GridView1.DataBind()

若要使用新的 BLL 类,只需将第一行代码替换为 ProductsTableAdapter 对象 ProductBLL 即可:

Dim productLogic As New ProductsBLL()
GridView1.DataSource = productLogic.GetProducts()
GridView1.DataBind()

还可以以声明方式访问 BLL 类, (类型化数据集也可以使用 ObjectDataSource) 。 我们将在以下教程中更详细地讨论 ObjectDataSource。

产品列表显示在 GridView 中

图 3:产品列表显示在 GridView 中 (单击以查看全尺寸图像)

步骤 3:向 DataRow 类添加 Field-Level 验证

字段级验证是插入或更新时与业务对象的属性值相关的检查。 产品的一些字段级验证规则包括:

  • 字段 ProductName 的长度必须为 40 个字符或更少
  • 字段 QuantityPerUnit 的长度必须为 20 个字符或更少
  • ProductIDProductNameDiscontinued 字段是必需的,但所有其他字段都是可选的
  • UnitPriceUnitsInStockUnitsOnOrderReorderLevel 字段必须大于或等于零

这些规则可以而且应该在数据库级别表示。 和 字段的ProductName字符限制分别由表中这些列Products的数据类型捕获 (nvarchar(40)nvarchar(20)) 。QuantityPerUnit 如果数据库表列允许 NULL ,则表示字段是否为必填字段和可选字段。 存在四个检查约束,确保只有大于或等于零的值才能将其转换为 UnitPriceUnitsInStockUnitsOnOrderReorderLevel 列。

除了在数据库中强制实施这些规则外,还应在 DataSet 级别强制实施这些规则。 事实上,已为每个 DataTable 的 DataColumns 集捕获字段长度以及值是必需值还是可选值。 若要查看自动提供的现有字段级验证,请转到 DataSet Designer,从其中一个 DataTable 中选择一个字段,然后转到属性窗口。 如图 4 所示, QuantityPerUnit 中的 ProductsDataTable DataColumn 的最大长度为 20 个字符,并且允许 NULL 值。 如果尝试将 的 QuantityPerUnit 属性设置为ProductsDataRow长度超过 20 个字符的字符串值,ArgumentException则会引发 。

DataColumn 提供基本 Field-Level 验证

图 4:DataColumn 提供基本 Field-Level 验证 (单击以查看全尺寸图像)

遗憾的是,无法通过属性窗口指定边界检查,例如UnitPrice值必须大于或等于零。 为了提供这种类型的字段级验证,我们需要为 DataTable 的 ColumnChanging 事件创建事件处理程序。 如 前面的教程中所述,可以通过使用分部类扩展类型化数据集创建的 DataSet、DataTable 和 DataRow 对象。 使用此方法,我们可以为 ProductsDataTable 类创建ColumnChanging事件处理程序。 首先在名为 ProductsDataTable.ColumnChanging.vbApp_Code文件夹中创建类。

将新类添加到App_Code文件夹

图 5:向文件夹添加新类 App_Code (单击以查看全尺寸图像)

接下来,为 ColumnChanging 事件创建一个事件处理程序,以确保 UnitPrice (NULL 的 、UnitsInStockUnitsOnOrderReorderLevel 列值) 大于或等于零。 如果任何此类列在范围外,则引发 ArgumentException

ProductsDataTable.ColumnChanging.vb

Imports System.data

Partial Public Class Northwind
    Partial Public Class ProductsDataTable
        Public Overrides Sub BeginInit()
            AddHandler Me.ColumnChanging, AddressOf ValidateColumn
        End Sub

        Sub ValidateColumn(sender As Object, e As DataColumnChangeEventArgs)
            If e.Column.Equals(Me.UnitPriceColumn) Then
                If Not Convert.IsDBNull(e.ProposedValue) AndAlso _
                    CType(e.ProposedValue, Decimal) < 0 Then
                    Throw New ArgumentException( _
                        "UnitPrice cannot be less than zero", "UnitPrice")
                End If
            ElseIf e.Column.Equals(Me.UnitsInStockColumn) OrElse _
                e.Column.Equals(Me.UnitsOnOrderColumn) OrElse _
                e.Column.Equals(Me.ReorderLevelColumn) Then
                If Not Convert.IsDBNull(e.ProposedValue) AndAlso _
                    CType(e.ProposedValue, Short) < 0 Then
                    Throw New ArgumentException(String.Format( _
                        "{0} cannot be less than zero", e.Column.ColumnName), _
                        e.Column.ColumnName)
                End If
            End If
        End Sub
    End Class
End Class

步骤 4:将自定义业务规则添加到 BLL 的类

除了字段级验证外,还可能存在涉及不同实体或概念的高级自定义业务规则,这些实体或概念无法在单列级别表达,例如:

  • 如果产品已停产, UnitPrice 则无法更新
  • 员工的居住国家/地区必须与经理的居住国相同
  • 如果产品是供应商提供的唯一产品,则产品不能停产

BLL 类应包含检查,以确保遵守应用程序的业务规则。 这些检查可以直接添加到它们所应用的方法中。

假设我们的业务规则规定,如果某个产品是给定供应商提供的唯一产品,则无法将其标记为停产。 也就是说,如果产品 X 是我们从供应商 Y 购买的唯一产品,则我们不能将 X 标记为已停产:但是,如果供应商 Y 向我们提供了三种产品 ,即 ABC,那么我们可以将所有这些产品标记为已停产。 一个奇怪的业务规则,但业务规则和常识并不总是一致的!

若要在 方法中 UpdateProducts 强制实施此业务规则,首先检查是否 Discontinued 设置为 True ,如果是,我们将调用 GetProductsBySupplierID 以确定从此产品的供应商购买了多少产品。 如果只从此供应商购买一种 ApplicationException产品,我们将引发 。

<System.ComponentModel.DataObjectMethodAttribute_
    (System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateProduct( _
    productName As String, supplierID As Nullable(Of Integer), _
    categoryID As Nullable(Of Integer), quantityPerUnit As String, _
    unitPrice As Nullable(Of Decimal), unitsInStock As Nullable(Of Short), _
    unitsOnOrder As Nullable(Of Short), reorderLevel As Nullable(Of Short), _
    discontinued As Boolean, productID As Integer) _
    As Boolean

    Dim products As Northwind.ProductsDataTable = _
        Adapter.GetProductByProductID(productID)

    If products.Count = 0 Then
        Return False
    End If

    Dim product As Northwind.ProductsRow = products(0)

    If discontinued Then
        Dim productsBySupplier As Northwind.ProductsDataTable = _
            Adapter.GetProductsBySupplierID(product.SupplierID)

        If productsBySupplier.Count = 1 Then
            Throw New ApplicationException( _
                "You cannot mark a product as discontinued if it is " & _
                "the only product purchased from a supplier")
        End If
    End If

    product.ProductName = productName

    If Not supplierID.HasValue Then
        product.SetSupplierIDNull()
    Else
        product.SupplierID = supplierID.Value
    End If

    If Not categoryID.HasValue Then
        product.SetCategoryIDNull()
    Else
        product.CategoryID = categoryID.Value
    End If

    If quantityPerUnit Is Nothing Then
        product.SetQuantityPerUnitNull()
    Else
        product.QuantityPerUnit = quantityPerUnit
    End If

    If Not unitPrice.HasValue Then
        product.SetUnitPriceNull()
    Else
        product.UnitPrice = unitPrice.Value
    End If

    If Not unitsInStock.HasValue Then
        product.SetUnitsInStockNull()
    Else
        product.UnitsInStock = unitsInStock.Value
    End If

    If Not unitsOnOrder.HasValue Then
        product.SetUnitsOnOrderNull()
    Else
        product.UnitsOnOrder = unitsOnOrder.Value
    End If

    If Not reorderLevel.HasValue Then
        product.SetReorderLevelNull()
    Else
        product.ReorderLevel = reorderLevel.Value
    End If

    product.Discontinued = discontinued

    Dim rowsAffected As Integer = Adapter.Update(product)

    Return rowsAffected = 1
End Function

响应演示层中的验证错误

从表示层调用 BLL 时,我们可以决定是尝试处理可能引发的任何异常,还是让它们冒泡到 ASP.NET (这将引发 HttpApplication的事件 Error) 。 若要在以编程方式使用 BLL 时处理异常,可以使用 Try...Catch 块,如以下示例所示:

Dim productLogic As New ProductsBLL()

Try
    productLogic.UpdateProduct("Scotts Tea", 1, 1, Nothing, _
      -14, 10, Nothing, Nothing, False, 1)
Catch ae As ArgumentException
    Response.Write("There was a problem: " & ae.Message)
End Try

正如我们在将来的教程中所看到的,处理使用数据 Web 控件插入、更新或删除数据时从 BLL 冒升的异常可以直接在事件处理程序中处理,而不必将代码包装在块中 Try...Catch

总结

架构良好的应用程序被设计成不同的层,每个层都封装了一个特定的角色。 在本系列文章的第一个教程中,我们使用类型化数据集创建了数据访问层;在本教程中,我们在应用程序的 App_Code 文件夹中构建了一个业务逻辑层作为一系列类,这些类向下调用到 DAL 中。 BLL 为应用程序实现字段级和业务级逻辑。 除了创建单独的 BLL 之外,如本教程中所述,另一个选项是通过使用分部类扩展 TableAdapters 的方法。 但是,使用此方法不允许我们替代现有方法,也不能像本文中采用的方法那样干净地分隔 DAL 和 BLL。

DAL 和 BLL 完成后,我们就可以开始演示层了。 在下一教程中,我们将对数据访问主题进行简短的绕道,并定义一致的页面布局供整个教程使用。

编程快乐!

关于作者

斯科特·米切尔是七本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com 的创始人,自 1998 年以来一直在使用 Microsoft Web 技术。 Scott 担任独立顾问、培训师和作家。 他的最新一本书是 山姆斯在 24 小时内 ASP.NET 2.0。 可以在 上mitchell@4GuysFromRolla.com联系他,也可以通过他的博客(可在 中找到http://ScottOnWriting.NET)。

特别感谢

本教程系列由许多有用的审阅者审阅。 本教程的主要审阅者是 Liz Shulok、Dennis Patterson、Carlos Santos 和 Hilton Giesenow。 有兴趣查看我即将发布的 MSDN 文章? 如果是,请在 处mitchell@4GuysFromRolla.com放置一行。