"
ASP.NET (snapshot 2017) Microsoft documentation and samples

Creating a Business Logic Layer (VB)

by Scott Mitchell

Download Sample App or Download PDF

In this tutorial we’ll see how to centralize your business rules into a Business Logic Layer (BLL) that serves as an intermediary for data exchange between the presentation layer and the DAL.

Introduction

The Data Access Layer (DAL) created in the first tutorial cleanly separates the data access logic from the presentation logic. However, while the DAL cleanly separates the data access details from the presentation layer, it does not enforce any business rules that may apply. For example, for our application we may want to disallow the CategoryID or SupplierID fields of the Products table to be modified when the Discontinued field is set to 1, or we might want to enforce seniority rules, prohibiting situations in which an employee is managed by someone who was hired after them. Another common scenario is authorization perhaps only users in a particular role can delete products or can change the UnitPrice value.

In this tutorial we’ll see how to centralize these business rules into a Business Logic Layer (BLL) that serves as an intermediary for data exchange between the presentation layer and the DAL. In a real-world application, the BLL should be implemented as a separate Class Library project; however, for these tutorials we’ll implement the BLL as a series of classes in our App_Code folder in order to simplify the project structure. Figure 1 illustrates the architectural relationships among the presentation layer, BLL, and DAL.

The BLL Separates the Presentation Layer from the Data Access Layer and Imposes Business Rules
The BLL Separates the Presentation Layer from the Data Access Layer and Imposes Business Rules

Figure 1: The BLL Separates the Presentation Layer from the Data Access Layer and Imposes Business Rules

Rather than creating separate classes to implement our business logic, we could alternatively place this logic directly in the Typed DataSet with partial classes. For an example of creating and extending a Typed DataSet, refer back to the first tutorial.

Step 1: Creating the BLL Classes

Our BLL will be composed of four classes, one for each TableAdapter in the DAL; each of these BLL classes will have methods for retrieving, inserting, updating, and deleting from the respective TableAdapter in the DAL, applying the appropriate business rules.

To more cleanly separate the DAL- and BLL-related classes, let’s create two subfolders in the App_Code folder, DAL and BLL. Simply right-click on the App_Code folder in the Solution Explorer and choose New Folder. After creating these two folders, move the Typed DataSet created in the first tutorial into the DAL subfolder.

Next, create the four BLL class files in the BLL subfolder. To accomplish this, right-click on the BLL subfolder, choose Add a New Item, and choose the Class template. Name the four classes ProductsBLL, CategoriesBLL, SuppliersBLL, and EmployeesBLL.

Add Four New Classes to the App_Code Folder
Add Four New Classes to the App_Code Folder

Figure 2: Add Four New Classes to the App_Code Folder

Next, let’s add methods to each of the classes to simply wrap the methods defined for the TableAdapters from the first tutorial. For now, these methods will just call directly into the DAL; we’ll return later to add any needed business logic.

[!NOTE] If you are using Visual Studio Standard Edition or above (that is, you’re not using Visual Web Developer), you can optionally design your classes visually using the Class Designer. Refer to the Class Designer Blog for more information on this new feature in Visual Studio.

For the ProductsBLL class we need to add a total of seven methods:

ProductsBLL.vb

[!code-vbMain]

   1:  Imports NorthwindTableAdapters
   2:   
   3:  <System.ComponentModel.DataObject()> _
   4:  Public Class ProductsBLL
   5:   
   6:      Private _productsAdapter As ProductsTableAdapter = Nothing
   7:      Protected ReadOnly Property Adapter() As ProductsTableAdapter
   8:          Get
   9:              If _productsAdapter Is Nothing Then
  10:                  _productsAdapter = New ProductsTableAdapter()
  11:              End If
  12:   
  13:              Return _productsAdapter
  14:          End Get
  15:      End Property
  16:   
  17:      <System.ComponentModel.DataObjectMethodAttribute _
  18:          (System.ComponentModel.DataObjectMethodType.Select, True)> _
  19:      Public Function GetProducts() As Northwind.ProductsDataTable
  20:          Return Adapter.GetProducts()
  21:      End Function
  22:   
  23:      <System.ComponentModel.DataObjectMethodAttribute _
  24:          (System.ComponentModel.DataObjectMethodType.Select, False)> _
  25:      Public Function GetProductByProductID(ByVal productID As Integer) _
  26:          As Northwind.ProductsDataTable
  27:          Return Adapter.GetProductByProductID(productID)
  28:      End Function
  29:   
  30:      <System.ComponentModel.DataObjectMethodAttribute _
  31:          (System.ComponentModel.DataObjectMethodType.Select, False)> _
  32:      Public Function GetProductsByCategoryID(ByVal categoryID As Integer) _
  33:          As Northwind.ProductsDataTable
  34:          Return Adapter.GetProductsByCategoryID(categoryID)
  35:      End Function
  36:   
  37:      <System.ComponentModel.DataObjectMethodAttribute _
  38:          (System.ComponentModel.DataObjectMethodType.Select, False)> _
  39:      Public Function GetProductsBySupplierID(ByVal supplierID As Integer) _
  40:          As Northwind.ProductsDataTable
  41:          Return Adapter.GetProductsBySupplierID(supplierID)
  42:      End Function
  43:   
  44:      <System.ComponentModel.DataObjectMethodAttribute _
  45:          (System.ComponentModel.DataObjectMethodType.Insert, True)> _
  46:      Public Function AddProduct( _
  47:          productName As String, supplierID As Nullable(Of Integer), _
  48:          categoryID As Nullable(Of Integer), quantityPerUnit As String, _
  49:          unitPrice As Nullable(Of Decimal), unitsInStock As Nullable(Of Short), _
  50:          unitsOnOrder As Nullable(Of Short), reorderLevel As Nullable(Of Short), _
  51:          discontinued As Boolean) _
  52:          As Boolean
  53:   
  54:          Dim products As New Northwind.ProductsDataTable()
  55:          Dim product As Northwind.ProductsRow = products.NewProductsRow()
  56:   
  57:          product.ProductName = productName
  58:          If Not supplierID.HasValue Then
  59:              product.SetSupplierIDNull()
  60:          Else
  61:              product.SupplierID = supplierID.Value
  62:          End If
  63:   
  64:          If Not categoryID.HasValue Then
  65:              product.SetCategoryIDNull()
  66:          Else
  67:              product.CategoryID = categoryID.Value
  68:          End If
  69:   
  70:          If quantityPerUnit Is Nothing Then
  71:              product.SetQuantityPerUnitNull()
  72:          Else
  73:              product.QuantityPerUnit = quantityPerUnit
  74:          End If
  75:   
  76:          If Not unitPrice.HasValue Then
  77:              product.SetUnitPriceNull()
  78:          Else
  79:              product.UnitPrice = unitPrice.Value
  80:          End If
  81:   
  82:          If Not unitsInStock.HasValue Then
  83:              product.SetUnitsInStockNull()
  84:          Else
  85:              product.UnitsInStock = unitsInStock.Value
  86:          End If
  87:   
  88:          If Not unitsOnOrder.HasValue Then
  89:              product.SetUnitsOnOrderNull()
  90:          Else
  91:              product.UnitsOnOrder = unitsOnOrder.Value
  92:          End If
  93:   
  94:          If Not reorderLevel.HasValue Then
  95:              product.SetReorderLevelNull()
  96:          Else
  97:              product.ReorderLevel = reorderLevel.Value
  98:          End If
  99:   
 100:          product.Discontinued = discontinued
 101:   
 102:          products.AddProductsRow(product)
 103:          Dim rowsAffected As Integer = Adapter.Update(products)
 104:   
 105:          Return rowsAffected = 1
 106:      End Function
 107:   
 108:      <System.ComponentModel.DataObjectMethodAttribute _
 109:          (System.ComponentModel.DataObjectMethodType.Update, True)> _
 110:      Public Function UpdateProduct(_
 111:          productName As String, supplierID As Nullable(Of Integer), _
 112:          categoryID As Nullable(Of Integer), quantityPerUnit As String, _
 113:          unitPrice As Nullable(Of Decimal), unitsInStock As Nullable(Of Short), _
 114:          unitsOnOrder As Nullable(Of Short), reorderLevel As Nullable(Of Short), _
 115:          discontinued As Boolean, productID As Integer) _
 116:          As Boolean
 117:   
 118:          Dim products As Northwind.ProductsDataTable = _
 119:              Adapter.GetProductByProductID(productID)
 120:   
 121:          If products.Count = 0 Then
 122:              Return False
 123:          End If
 124:   
 125:          Dim product as Northwind.ProductsRow = products(0)
 126:   
 127:          product.ProductName = productName
 128:          If Not supplierID.HasValue Then
 129:              product.SetSupplierIDNull()
 130:          Else
 131:              product.SupplierID = supplierID.Value
 132:          End If
 133:   
 134:          If Not categoryID.HasValue Then
 135:              product.SetCategoryIDNull()
 136:          Else
 137:              product.CategoryID = categoryID.Value
 138:          End If
 139:   
 140:          If quantityPerUnit Is Nothing Then
 141:              product.SetQuantityPerUnitNull()
 142:          Else
 143:              product.QuantityPerUnit = quantityPerUnit
 144:          End If
 145:   
 146:          If Not unitPrice.HasValue Then
 147:              product.SetUnitPriceNull()
 148:          Else
 149:              product.UnitPrice = unitPrice.Value
 150:          End If
 151:   
 152:          If Not unitsInStock.HasValue Then
 153:              product.SetUnitsInStockNull()
 154:          Else
 155:              product.UnitsInStock = unitsInStock.Value
 156:          End If
 157:   
 158:          If Not unitsOnOrder.HasValue Then
 159:              product.SetUnitsOnOrderNull()
 160:          Else
 161:              product.UnitsOnOrder = unitsOnOrder.Value
 162:          End If
 163:   
 164:          If Not reorderLevel.HasValue Then
 165:              product.SetReorderLevelNull()
 166:          Else
 167:              product.ReorderLevel = reorderLevel.Value
 168:          End If
 169:   
 170:          product.Discontinued = discontinued
 171:   
 172:          Dim rowsAffected As Integer = Adapter.Update(product)
 173:   
 174:          Return rowsAffected = 1
 175:      End Function
 176:   
 177:      <System.ComponentModel.DataObjectMethodAttribute _
 178:          (System.ComponentModel.DataObjectMethodType.Delete, True)> _
 179:      Public Function DeleteProduct(ByVal productID As Integer) As Boolean
 180:          Dim rowsAffected As Integer = Adapter.Delete(productID)
 181:   
 182:          Return rowsAffected = 1
 183:      End Function
 184:  End Class

The methods that simply return data GetProducts, GetProductByProductID, GetProductsByCategoryID, and GetProductBySuppliersID are fairly straightforward as they simply call down into the DAL. While in some scenarios there may be business rules that need to be implemented at this level (such as authorization rules based on the currently logged on user or the role to which the user belongs), we’ll simply leave these methods as-is. For these methods, then, the BLL serves merely as a proxy through which the presentation layer accesses the underlying data from the Data Access Layer.

The AddProduct and UpdateProduct methods both take in as parameters the values for the various product fields and add a new product or update an existing one, respectively. Since many of the Product table’s columns can accept NULL values (CategoryID, SupplierID, and UnitPrice, to name a few), those input parameters for AddProduct and UpdateProduct that map to such columns use nullable types. Nullable types are new to .NET 2.0 and provide a technique for indicating whether a value type should, instead, be Nothing. Refer to the Paul Vick’s blog entry The Truth About Nullable Types and VB and the technical documentation for the Nullable structure for more information.

All three methods return a Boolean value indicating whether a row was inserted, updated, or deleted since the operation may not result in an affected row. For example, if the page developer calls DeleteProduct passing in a ProductID for a non-existent product, the DELETE statement issued to the database will have no affect and therefore the DeleteProduct method will return False.

Note that when adding a new product or updating an existing one we take in the new or modified product’s field values as a list of scalars as opposed to accepting a ProductsRow instance. This approach was chosen because the ProductsRow class derives from the ADO.NET DataRow class, which doesn’t have a default parameterless constructor. In order to create a new ProductsRow instance, we must first create a ProductsDataTable instance and then invoke its NewProductRow() method (which we do in AddProduct). This shortcoming rears its head when we turn to inserting and updating products using the ObjectDataSource. In short, the ObjectDataSource will try to create an instance of the input parameters. If the BLL method expects a ProductsRow instance, the ObjectDataSource will try to create one, but fail due to the lack of a default parameterless constructor. For more information on this problem, refer to the following two ASP.NET Forums posts: Updating ObjectDataSources with Strongly-Typed DataSets, and Problem With ObjectDataSource and Strongly-Typed DataSet.

Next, in both AddProduct and UpdateProduct, the code creates a ProductsRow instance and populates it with the values just passed in. When assigning values to DataColumns of a DataRow various field-level validation checks can occur. Therefore, manually putting the passed in values back into a DataRow helps ensure the validity of the data being passed to the BLL method. Unfortunately the strongly-typed DataRow classes generated by Visual Studio do not use nullable types. Rather, to indicate that a particular DataColumn in a DataRow should correspond to a NULL database value we must use the SetColumnNameNull() method.

In UpdateProduct we first load in the product to update using GetProductByProductID(productID). While this may seem like an unnecessary trip to the database, this extra trip will prove worthwhile in future tutorials that explore optimistic concurrency. Optimistic concurrency is a technique to ensure that two users who are simultaneously working on the same data don’t accidentally overwrite one another’s changes. Grabbing the entire record also makes it easier to create update methods in the BLL that only modify a subset of the DataRow’s columns. When we explore the SuppliersBLL class we’ll see such an example.

Finally, note that the ProductsBLL class has the DataObject attribute applied to it (the [System.ComponentModel.DataObject] syntax right before the class statement near the top of the file) and the methods have DataObjectMethodAttribute attributes. The DataObject attribute marks the class as being an object suitable for binding to an ObjectDataSource control, whereas the DataObjectMethodAttribute indicates the purpose of the method. As we’ll see in future tutorials, ASP.NET 2.0’s ObjectDataSource makes it easy to declaratively access data from a class. To help filter the list of possible classes to bind to in the ObjectDataSource’s wizard, by default only those classes marked as DataObjects are shown in the wizard’s drop-down list. The ProductsBLL class will work just as well without these attributes, but adding them makes it easier to work with in the ObjectDataSource’s wizard.

Adding the Other Classes

With the ProductsBLL class complete, we still need to add the classes for working with categories, suppliers, and employees. Take a moment to create the following classes and methods using the concepts from the example above:

The one method worth noting is the SuppliersBLL class’s UpdateSupplierAddress method. This method provides an interface for updating just the supplier’s address information. Internally, this method reads in the SupplierDataRow object for the specified supplierID (using GetSupplierBySupplierID), sets its address-related properties, and then calls down into the SupplierDataTable’s Update method. The UpdateSupplierAddress method follows:

[!code-vbMain]

   1:  <System.ComponentModel.DataObjectMethodAttribute _
   2:      (System.ComponentModel.DataObjectMethodType.Update, True)> _
   3:  Public Function UpdateSupplierAddress(ByVal supplierID As Integer, _
   4:      ByVal address As String, ByVal city As String, ByVal country As String) _
   5:      As Boolean
   6:   
   7:      Dim suppliers As Northwind.SuppliersDataTable = _
   8:          Adapter.GetSupplierBySupplierID(supplierID)
   9:   
  10:      If suppliers.Count = 0 Then
  11:          Return False
  12:      Else
  13:          Dim supplier As Northwind.SuppliersRow = suppliers(0)
  14:   
  15:          If address Is Nothing Then
  16:              supplier.SetAddressNull()
  17:          Else
  18:              supplier.Address = address
  19:          End If
  20:   
  21:          If city Is Nothing Then
  22:              supplier.SetCityNull()
  23:          Else
  24:              supplier.City = city
  25:          End If
  26:   
  27:          If country Is Nothing Then
  28:              supplier.SetCountryNull()
  29:          Else
  30:              supplier.Country = country
  31:          End If
  32:   
  33:          Dim rowsAffected As Integer = Adapter.Update(supplier)
  34:   
  35:          Return rowsAffected = 1
  36:      End If
  37:  End Function

Refer to this article’s download for my complete implementation of the BLL classes.

Step 2: Accessing the Typed DataSets Through the BLL Classes

In the first tutorial we saw examples of working directly with the Typed DataSet programmatically, but with the addition of our BLL classes, the presentation tier should work against the BLL instead. In the AllProducts.aspx example from the first tutorial, the ProductsTableAdapter was used to bind the list of products to a GridView, as shown in the following code:

[!code-vbMain]

   1:  Dim productsAdapter As New ProductsTableAdapter()
   2:  GridView1.DataSource = productsAdapter.GetProducts()
   3:  GridView1.DataBind()

To use the new BLL classes, all that needs to be changed is the first line of code simply replace the ProductsTableAdapter object with a ProductBLL object:

[!code-vbMain]

   1:  Dim productLogic As New ProductsBLL()
   2:  GridView1.DataSource = productLogic.GetProducts()
   3:  GridView1.DataBind()

The BLL classes can also be accessed declaratively (as can the Typed DataSet) by using the ObjectDataSource. We’ll be discussing the ObjectDataSource in greater detail in the following tutorials.

The List of Products is Displayed in a GridView

Figure 3: The List of Products is Displayed in a GridView (Click to view full-size image)

Step 3: Adding Field-Level Validation to the DataRow Classes

Field-level validation are checks that pertains to the property values of the business objects when inserting or updating. Some field-level validation rules for products include:

These rules can and should be expressed at the database level. The character limit on the ProductName and QuantityPerUnit fields are captured by the data types of those columns in the Products table (nvarchar(40) and nvarchar(20), respectively). Whether fields are required and optional are expressed by if the database table column allows NULL s. Four check constraints exist that ensure that only values greater than or equal to zero can make it into the UnitPrice, UnitsInStock, UnitsOnOrder, or ReorderLevel columns.

In addition to enforcing these rules at the database they should also be enforced at the DataSet level. In fact, the field length and whether a value is required or optional are already captured for each DataTable’s set of DataColumns. To see the existing field-level validation automatically provided, go to the DataSet Designer, select a field from one of the DataTables and then go to the Properties window. As Figure 4 shows, the QuantityPerUnit DataColumn in the ProductsDataTable has a maximum length of 20 characters and does allow NULL values. If we attempt to set the ProductsDataRow’s QuantityPerUnit property to a string value longer than 20 characters an ArgumentException will be thrown.

The DataColumn Provides Basic Field-Level Validation

Figure 4: The DataColumn Provides Basic Field-Level Validation (Click to view full-size image)

Unfortunately, we can’t specify bounds checks, such as the UnitPrice value must be greater than or equal to zero, through the Properties window. In order to provide this type of field-level validation we need to create an event handler for the DataTable’s ColumnChanging event. As mentioned in the preceding tutorial, the DataSet, DataTables, and DataRow objects created by the Typed DataSet can be extended through the use of partial classes. Using this technique we can create a ColumnChanging event handler for the ProductsDataTable class. Start by creating a class in the App_Code folder named ProductsDataTable.ColumnChanging.vb.

Add a New Class to the App_Code Folder

Figure 5: Add a New Class to the App_Code Folder (Click to view full-size image)

Next, create an event handler for the ColumnChanging event that ensures that the UnitPrice, UnitsInStock, UnitsOnOrder, and ReorderLevel column values (if not NULL) are greater than or equal to zero. If any such column is out of range, throw an ArgumentException.

ProductsDataTable.ColumnChanging.vb

[!code-vbMain]

   1:  Imports System.data
   2:   
   3:  Partial Public Class Northwind
   4:      Partial Public Class ProductsDataTable
   5:          Public Overrides Sub BeginInit()
   6:              AddHandler Me.ColumnChanging, AddressOf ValidateColumn
   7:          End Sub
   8:   
   9:          Sub ValidateColumn(sender As Object, e As DataColumnChangeEventArgs)
  10:              If e.Column.Equals(Me.UnitPriceColumn) Then
  11:                  If Not Convert.IsDBNull(e.ProposedValue) AndAlso _
  12:                      CType(e.ProposedValue, Decimal) < 0 Then
  13:                      Throw New ArgumentException( _
  14:                          "UnitPrice cannot be less than zero", "UnitPrice")
  15:                  End If
  16:              ElseIf e.Column.Equals(Me.UnitsInStockColumn) OrElse _
  17:                  e.Column.Equals(Me.UnitsOnOrderColumn) OrElse _
  18:                  e.Column.Equals(Me.ReorderLevelColumn) Then
  19:                  If Not Convert.IsDBNull(e.ProposedValue) AndAlso _
  20:                      CType(e.ProposedValue, Short) < 0 Then
  21:                      Throw New ArgumentException(String.Format( _
  22:                          "{0} cannot be less than zero", e.Column.ColumnName), _
  23:                          e.Column.ColumnName)
  24:                  End If
  25:              End If
  26:          End Sub
  27:      End Class
  28:  End Class

Step 4: Adding Custom Business Rules to the BLL’s Classes

In addition to field-level validation, there may be high-level custom business rules that involve different entities or concepts not expressible at the single column level, such as:

The BLL classes should contain checks to ensure adherence to the application’s business rules. These checks can be added directly to the methods to which they apply.

Imagine that our business rules dictate that a product could not be marked discontinued if it was the only product from a given supplier. That is, if product X was the only product we purchased from supplier Y, we could not mark X as discontinued; if, however, supplier Y supplied us with three products, A, B, and C, then we could mark any and all of these as discontinued. An odd business rule, but business rules and common sense aren’t always aligned!

To enforce this business rule in the UpdateProducts method we’d start by checking if Discontinued was set to True and, if so, we’d call GetProductsBySupplierID to determine how many products we purchased from this product’s supplier. If only one product is purchased from this supplier, we throw an ApplicationException.

[!code-vbMain]

   1:  <System.ComponentModel.DataObjectMethodAttribute_
   2:      (System.ComponentModel.DataObjectMethodType.Update, True)> _
   3:  Public Function UpdateProduct( _
   4:      productName As String, supplierID As Nullable(Of Integer), _
   5:      categoryID As Nullable(Of Integer), quantityPerUnit As String, _
   6:      unitPrice As Nullable(Of Decimal), unitsInStock As Nullable(Of Short), _
   7:      unitsOnOrder As Nullable(Of Short), reorderLevel As Nullable(Of Short), _
   8:      discontinued As Boolean, productID As Integer) _
   9:      As Boolean
  10:   
  11:      Dim products As Northwind.ProductsDataTable = _
  12:          Adapter.GetProductByProductID(productID)
  13:   
  14:      If products.Count = 0 Then
  15:          Return False
  16:      End If
  17:   
  18:      Dim product As Northwind.ProductsRow = products(0)
  19:   
  20:      If discontinued Then
  21:          Dim productsBySupplier As Northwind.ProductsDataTable = _
  22:              Adapter.GetProductsBySupplierID(product.SupplierID)
  23:   
  24:          If productsBySupplier.Count = 1 Then
  25:              Throw New ApplicationException( _
  26:                  "You cannot mark a product as discontinued if it is " & _
  27:                  "the only product purchased from a supplier")
  28:          End If
  29:      End If
  30:   
  31:      product.ProductName = productName
  32:   
  33:      If Not supplierID.HasValue Then
  34:          product.SetSupplierIDNull()
  35:      Else
  36:          product.SupplierID = supplierID.Value
  37:      End If
  38:   
  39:      If Not categoryID.HasValue Then
  40:          product.SetCategoryIDNull()
  41:      Else
  42:          product.CategoryID = categoryID.Value
  43:      End If
  44:   
  45:      If quantityPerUnit Is Nothing Then
  46:          product.SetQuantityPerUnitNull()
  47:      Else
  48:          product.QuantityPerUnit = quantityPerUnit
  49:      End If
  50:   
  51:      If Not unitPrice.HasValue Then
  52:          product.SetUnitPriceNull()
  53:      Else
  54:          product.UnitPrice = unitPrice.Value
  55:      End If
  56:   
  57:      If Not unitsInStock.HasValue Then
  58:          product.SetUnitsInStockNull()
  59:      Else
  60:          product.UnitsInStock = unitsInStock.Value
  61:      End If
  62:   
  63:      If Not unitsOnOrder.HasValue Then
  64:          product.SetUnitsOnOrderNull()
  65:      Else
  66:          product.UnitsOnOrder = unitsOnOrder.Value
  67:      End If
  68:   
  69:      If Not reorderLevel.HasValue Then
  70:          product.SetReorderLevelNull()
  71:      Else
  72:          product.ReorderLevel = reorderLevel.Value
  73:      End If
  74:   
  75:      product.Discontinued = discontinued
  76:   
  77:      Dim rowsAffected As Integer = Adapter.Update(product)
  78:   
  79:      Return rowsAffected = 1
  80:  End Function

Responding to Validation Errors in the Presentation Tier

When calling the BLL from the presentation tier we can decide whether to attempt to handle any exceptions that might be raised or let them bubble up to ASP.NET (which will raise the HttpApplication’s Error event). To handle an exception when working with the BLL programmatically, we can use a Try…Catch block, as the following example shows:

[!code-vbMain]

   1:  Dim productLogic As New ProductsBLL()
   2:   
   3:  Try
   4:      productLogic.UpdateProduct("Scotts Tea", 1, 1, Nothing, _
   5:        -14, 10, Nothing, Nothing, False, 1)
   6:  Catch ae As ArgumentException
   7:      Response.Write("There was a problem: " & ae.Message)
   8:  End Try

As we’ll see in future tutorials, handling exceptions that bubble up from the BLL when using a data Web control for inserting, updating, or deleting data can be handled directly in an event handler as opposed to having to wrap code in Try...Catch blocks.

Summary

A well architected application is crafted into distinct layers, each of which encapsulates a particular role. In the first tutorial of this article series we created a Data Access Layer using Typed DataSets; in this tutorial we built a Business Logic Layer as a series of classes in our application’s App_Code folder that call down into our DAL. The BLL implements the field-level and business-level logic for our application. In addition to creating a separate BLL, as we did in this tutorial, another option is to extend the TableAdapters’ methods through the use of partial classes. However, using this technique does not allow us to override existing methods nor does it separate our DAL and our BLL as cleanly as the approach we’ve taken in this article.

With the DAL and BLL complete, we’re ready to start on our presentation layer. In the next tutorial we’ll take a brief detour from data access topics and define a consistent page layout for use throughout the tutorials.

Happy Programming!

About the Author

Scott Mitchell, author of seven ASP/ASP.NET books and founder of 4GuysFromRolla.com, has been working with Microsoft Web technologies since 1998. Scott works as an independent consultant, trainer, and writer. His latest book is Sams Teach Yourself ASP.NET 2.0 in 24 Hours. He can be reached at mitchell@4GuysFromRolla.com. or via his blog, which can be found at http://ScottOnWriting.NET.

Special Thanks To

This tutorial series was reviewed by many helpful reviewers. Lead reviewers for this tutorial were Liz Shulok, Dennis Patterson, Carlos Santos, and Hilton Giesenow. Interested in reviewing my upcoming MSDN articles? If so, drop me a line at mitchell@4GuysFromRolla.com.

Previous Next



Comments ( )
Link to this page: //www.vb-net.com/AspNet-DocAndSamples-2017/aspnet/web-forms/overview/data-access/introduction/creating-a-business-logic-layer-vb.htm
< THANKS ME>