Main ASP .NET Tutorial Index 

Tutorial 2: Creating a Business Logic Layer

 

Scott Mitchell

June 2006

Download the ASPNET_Data_Tutorial_2_CS.exe sample code.

Contents of Tutorial 2 (Visual C#)

Introduction
Step 1: Creating the BLL Classes
Step 2: Accessing the Typed DataSets Through the BLL Classes
Step 3: Adding Field-Level Validation to the DataRow Classes
Step 4: Adding Custom Business Rules to the BLL's Classes
Summary

 

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:

  • If a product is discontinued, its UnitPrice cannot be updated
  • An employee's country of residence must be the same as their manager's country of residence
  • A product cannot be discontinued if it is the only product provided by the supplier

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.

public bool UpdateProduct(string productName, int? supplierID, int? categoryID, string quantityPerUnit,
                              decimal? unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel,
                              bool discontinued, int productID)
{
        Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
        if (products.Count == 0)
            // no matching record found, return false
            return false;

        Northwind.ProductsRow product = products[0];

        // Business rule check - cannot discontinue a product that's supplied by only
        // one supplier
        if (discontinued)
        {
            // Get the products we buy from this supplier
            Northwind.ProductsDataTable productsBySupplier = Adapter.GetProductsBySupplierID(product.SupplierID);

            if (productsBySupplier.Count == 1)
                // this is the only product we buy from this supplier
                throw new ApplicationException("You cannot mark a product as discontinued if its the only product purchased from a supplier");
        }

        product.ProductName = productName;
        if (supplierID == null) product.SetSupplierIDNull(); else product.SupplierID = supplierID.Value;
        if (categoryID == null) product.SetCategoryIDNull(); else product.CategoryID = categoryID.Value;
        if (quantityPerUnit == null) product.SetQuantityPerUnitNull(); else product.QuantityPerUnit = quantityPerUnit;
        if (unitPrice == null) product.SetUnitPriceNull(); else product.UnitPrice = unitPrice.Value;
        if (unitsInStock == null) product.SetUnitsInStockNull(); else product.UnitsInStock = unitsInStock.Value;
        if (unitsOnOrder == null) product.SetUnitsOnOrderNull(); else product.UnitsOnOrder = unitsOnOrder.Value;
        if (reorderLevel == null) product.SetReorderLevelNull(); else product.ReorderLevel = reorderLevel.Value;
        product.Discontinued = discontinued;

        // Update the product record
        int rowsAffected = Adapter.Update(product);

        // Return true if precisely one row was updated, otherwise false
        return rowsAffected == 1;
} 

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:

ProductsBLL productLogic = new ProductsBLL();

// Update ProductID 1's information
try
{
    // This will fail since we're attempting to use a
    // UnitPrice value less than 0.
    productLogic.UpdateProduct("Scott's Tea", 1, 1, null, -14m, 10, null, null, false, 1);
}
catch (ArgumentException ae)
{
    Response.Write("There was a problem: " + ae.Message);
}

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 six 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, recently completing his latest book, 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 include 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.

 

 

Go to top of page or start of tutorial

 

 

 

 
eXTReMe Tracker