Поделиться через


Создание уровня бизнес-логики (C#)

Скотт Митчелл

Загрузить PDF-файл

В этом руководстве мы посмотрим, как централизовать бизнес-правила в уровне бизнес-логики (BLL), который служит посредником для обмена данными между уровнем представления и DAL.

Введение

Уровень доступа к данным (DAL), созданный в первом руководстве , четко отделяет логику доступа к данным от логики представления. Однако, хотя DAL четко отделяет сведения о доступе к данным от уровня представления, он не применяет бизнес-правила, которые могут применяться. Например, для нашего приложения может потребоваться запретить CategoryID изменение полей Products или таблицыSupplierID, если Discontinued для поля задано значение 1, или мы можем захотеть применить правила старшинства, запрещающие ситуации, когда сотрудник управляется кем-то, кто был нанят после них. Другой распространенный сценарий — авторизация, возможно, только пользователи с определенной ролью могут удалять продукты или изменять UnitPrice значение.

В этом руководстве мы посмотрим, как централизовать эти бизнес-правила в уровне бизнес-логики (BLL), который служит посредником для обмена данными между уровнем представления и DAL. В реальном приложении BLL следует реализовать как отдельный проект библиотеки классов; Однако в этих руководствах мы реализуем BLL в виде серии классов в нашей App_Code папке, чтобы упростить структуру проекта. На рисунке 1 показаны архитектурные связи между уровнем представления, BLL и DAL.

BLL отделяет уровень представления от уровня доступа к данным и накладывает бизнес-правила.

Рис. 1. BLL отделяет уровень представления от уровня доступа к данным и накладывает бизнес-правила

Шаг 1. Создание классов BLL

Наш BLL будет состоять из четырех классов, по одному для каждого TableAdapter в DAL; Каждый из этих классов BLL будет иметь методы для извлечения, вставки, обновления и удаления из соответствующего объекта TableAdapter в DAL, применяя соответствующие бизнес-правила.

Чтобы более четко разделить классы, связанные с DAL и BLL, создадим две вложенные папки в папке App_Code и DALBLL. Просто щелкните правой кнопкой мыши папку App_Code в Обозреватель решений и выберите Создать папку. После создания этих двух папок переместите типизированный набор данных, созданный в первом руководстве, во вложенную папку DAL .

Затем создайте четыре файла класса BLL во вложенной BLL папке. Для этого щелкните правой кнопкой мыши BLL вложенную папку, выберите Добавить новый элемент и выберите шаблон Класс. Назовите четыре класса ProductsBLL, CategoriesBLL, SuppliersBLLи EmployeesBLL.

Добавление четырех новых классов в папку App_Code

Рис. 2. Добавление четырех новых классов в папку App_Code

Далее давайте добавим методы в каждый из классов, чтобы просто упаковать методы, определенные для TableAdapters из первого учебника. Пока эти методы будут вызывать только непосредственно в DAL; Мы вернемся позже, чтобы добавить необходимую бизнес-логику.

Примечание

Если вы используете Visual Studio Standard Edition или более поздней версии (то есть вы не используете Visual Web Developer), при необходимости можно создать классы визуально с помощью Designer классов. Дополнительные сведения об этой новой функции в Visual Studio см. в блоге Designer классов.

ProductsBLL Для класса необходимо добавить в общей сложности семь методов:

  • GetProducts() возвращает все продукты
  • GetProductByProductID(productID) возвращает продукт с указанным идентификатором продукта
  • 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.cs

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindTableAdapters;

[System.ComponentModel.DataObject]
public class ProductsBLL
{
    private ProductsTableAdapter _productsAdapter = null;
    protected ProductsTableAdapter Adapter
    {
        get {
            if (_productsAdapter == null)
                _productsAdapter = new ProductsTableAdapter();

            return _productsAdapter;
        }
    }

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

    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Select, false)]
    public Northwind.ProductsDataTable GetProductByProductID(int productID)
    {
        return Adapter.GetProductByProductID(productID);
    }

    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Select, false)]
    public Northwind.ProductsDataTable GetProductsByCategoryID(int categoryID)
    {
        return Adapter.GetProductsByCategoryID(categoryID);
    }

    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Select, false)]
    public Northwind.ProductsDataTable GetProductsBySupplierID(int supplierID)
    {
        return Adapter.GetProductsBySupplierID(supplierID);
    }
    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Insert, true)]
    public bool AddProduct(string productName, int? supplierID, int? categoryID,
        string quantityPerUnit, decimal? unitPrice,  short? unitsInStock,
        short? unitsOnOrder, short? reorderLevel, bool discontinued)
    {
        // Create a new ProductRow instance
        Northwind.ProductsDataTable products = new Northwind.ProductsDataTable();
        Northwind.ProductsRow product = products.NewProductsRow();

        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;

        // Add the new product
        products.AddProductsRow(product);
        int rowsAffected = Adapter.Update(products);

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

    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.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.ProductsDataTable products = Adapter.GetProductByProductID(productID);
        if (products.Count == 0)
            // no matching record found, return false
            return false;

        Northwind.ProductsRow product = products[0];

        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;
    }

    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Delete, true)]
    public bool DeleteProduct(int productID)
    {
        int rowsAffected = Adapter.Delete(productID);

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

Методы, которые просто возвращают данные GetProducts, GetProductByProductID, GetProductsByCategoryIDи GetProductBySuppliersID , довольно просты, так как они просто вызывают в DAL. Хотя в некоторых сценариях могут существовать бизнес-правила, которые необходимо реализовать на этом уровне (например, правила авторизации на основе текущего вошедшего в систему пользователя или роли, к которой принадлежит пользователь), мы просто оставим эти методы как есть. Для этих методов BLL служит просто прокси-сервером, через который уровень представления обращается к базовым данным из уровня доступа к данным.

Оба AddProduct метода и UpdateProduct принимают в качестве параметров значения для различных полей продукта и добавляют новый продукт или обновляют существующий соответственно. Так как многие Product столбцы таблицы могут принимать NULL значения (CategoryID, SupplierIDи UnitPrice, чтобы назвать несколько), эти входные параметры для AddProduct и UpdateProduct , сопоставленные с такими столбцами, используют типы, допускающие значение NULL. Типы, допускающие значение NULL, являются новыми для .NET 2.0 и предоставляют метод для указания того, должен ли тип значения иметь nullзначение . В C# можно пометить тип значения как тип, допускающий значение NULL, добавив ? после типа (например int? x;, ). Дополнительные сведения см. в разделе Типы, допускаемые значение NULL , в руководстве по программированию на C# .

Все три метода возвращают логическое значение, указывающее, была ли строка вставлена, обновлена или удалена, так как операция может не привести к затронутой строке. Например, если разработчик страницы вызывает передачу ProductID для несуществующего продукта, инструкция, выданная в базу данных, DELETE не будет влиять, и, следовательноDeleteProduct, метод вернет false.DeleteProduct

Обратите внимание, что при добавлении нового продукта или обновлении существующего мы принимаем значения полей нового или измененного продукта как список скалярных значений, а не как принятие экземпляра ProductsRow . Этот подход был выбран, так как ProductsRow класс является производным от класса ADO.NET DataRow , который не имеет конструктора без параметров по умолчанию. Чтобы создать новый ProductsRow экземпляр, необходимо сначала создать ProductsDataTable экземпляр, а затем вызвать его NewProductRow() метод (что мы делаем в AddProduct). Этот недостаток поднимает голову, когда мы переходим к вставке и обновлению продуктов с помощью ObjectDataSource. Короче говоря, ObjectDataSource попытается создать экземпляр входных параметров. Если метод BLL ожидает ProductsRow экземпляр, ObjectDataSource попытается создать его, но завершится ошибкой из-за отсутствия конструктора без параметров по умолчанию. Дополнительные сведения об этой проблеме см. в следующих двух записях на форумах ASP.NET: Обновление ObjectDataSources с помощью Strongly-Typed Наборов данных и Проблема с ObjectDataSource и Strongly-Typed DataSet.

Затем в AddProduct и UpdateProductкод создает ProductsRow экземпляр и заполняет его только что переданными значениями. При назначении значений DataColumns dataRow могут выполняться различные проверки на уровне поля. Таким образом, помещение переданных значений вручную обратно в DataRow помогает обеспечить допустимость данных, передаваемых в метод BLL. К сожалению, строго типизированные классы DataRow, созданные Visual Studio, не используют типы, допускаемые значения NULL. Вместо этого, чтобы указать, что определенный объект DataColumn в DataRow должен соответствовать значению NULL базы данных, необходимо использовать SetColumnNameNull() метод .

В UpdateProduct первую очередь мы загружаем в продукт для обновления с помощью GetProductByProductID(productID). Хотя это может показаться ненужной поездкой в базу данных, эта дополнительная поездка окажется полезной в будущих учебниках, где рассматривается оптимистичный параллелизм. Оптимистичный параллелизм — это метод, позволяющий гарантировать, что два пользователя, одновременно работающие с одними и теми же данными, случайно не перезаписывают изменения друг друга. Захват всей записи также упрощает создание методов обновления в BLL, которые изменяют только подмножество столбцов DataRow. При изучении SuppliersBLL класса мы увидим такой пример.

Наконец, обратите внимание, что к классу ProductsBLL применен атрибут DataObject ( [System.ComponentModel.DataObject] синтаксис прямо перед оператором класса в верхней части файла), а методы имеют атрибуты DataObjectMethodAttribute. Атрибут DataObject помечает класс как объект, подходящий для привязки к элементу управления ObjectDataSource, тогда как DataObjectMethodAttribute указывает назначение метода . Как мы увидим в следующих руководствах, ASP.NET ObjectDataSource 2.0 упрощает декларативный доступ к данным из класса. Чтобы упростить фильтрацию списка возможных классов для привязки в мастере 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 . Этот метод предоставляет интерфейс для обновления только сведений об адресе поставщика. На внутреннем языке этот метод считывает объект SupplierDataRow для указанного supplierID объекта (с помощью GetSupplierBySupplierID), задает его свойства, связанные с адресом, а затем вызывает SupplierDataTableUpdate метод . Метод UpdateSupplierAddress выглядит следующим образом:

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Update, true)]
public bool UpdateSupplierAddress
    (int supplierID, string address, string city, string country)
{
    Northwind.SuppliersDataTable suppliers =
        Adapter.GetSupplierBySupplierID(supplierID);
    if (suppliers.Count == 0)
        // no matching record found, return false
        return false;
    else
    {
        Northwind.SuppliersRow supplier = suppliers[0];

        if (address == null) supplier.SetAddressNull();
          else supplier.Address = address;
        if (city == null) supplier.SetCityNull();
          else supplier.City = city;
        if (country == null) supplier.SetCountryNull();
          else supplier.Country = country;

        // Update the supplier Address-related information
        int rowsAffected = Adapter.Update(supplier);

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

Сведения о полной реализации классов BLL см. в скачивание этой статьи.

Шаг 2. Доступ к типизированным наборам данных через классы BLL

В первом руководстве мы видели примеры работы с типизированным набором данных программным способом, но с добавлением классов BLL уровень представления должен работать с BLL. AllProducts.aspx В примере из первого учебника ProductsTableAdapter использовался для привязки списка продуктов к GridView, как показано в следующем коде:

ProductsTableAdapter productsAdapter = new ProductsTableAdapter();
GridView1.DataSource = productsAdapter.GetProducts();
GridView1.DataBind();

Чтобы использовать новые классы BLL, необходимо изменить только первую строку кода, просто замените ProductsTableAdapter объект ProductBLL объектом :

ProductsBLL productLogic = new ProductsBLL();
GridView1.DataSource = productLogic.GetProducts();
GridView1.DataBind();

Доступ к классам BLL также можно получить декларативно (как и к типизированному набору данных) с помощью ObjectDataSource. Мы рассмотрим ObjectDataSource более подробно в следующих руководствах.

Список продуктов отображается в GridView

Рис. 3. Список продуктов отображается в GridView (щелкните, чтобы просмотреть полноразмерное изображение)

Шаг 3. Добавление проверки Field-Level в классы DataRow

Проверка на уровне полей — это проверки, относящиеся к значениям свойств бизнес-объектов при вставке или обновлении. Ниже перечислены некоторые правила проверки на уровне полей для продуктов:

  • Длина ProductName поля не должна превышать 40 символов.
  • Длина QuantityPerUnit поля не должна превышать 20 символов.
  • Поля ProductID, ProductNameи Discontinued являются обязательными, но все остальные поля являются необязательными.
  • Поля UnitPrice, UnitsInStock, UnitsOnOrderи ReorderLevel должны быть больше или равны нулю.

Эти правила могут и должны быть выражены на уровне базы данных. Ограничение символов ProductName в полях и QuantityPerUnit фиксируется типами данных этих столбцов в Products таблице (nvarchar(40) и nvarchar(20)соответственно). Сведения о том, являются ли поля обязательными и необязательными, выражаются в том, допускает NULL ли столбец таблицы базы данных значения . Существуют четыре ограничения проверка, которые гарантируют, что только значения, превышающие или равные нулю, могут попасть в UnitPriceстолбцы , UnitsInStock, UnitsOnOrderили ReorderLevel .

Помимо применения этих правил в базе данных, они также должны применяться на уровне DataSet. На самом деле длина поля и то, является ли значение обязательным или необязательным, уже фиксируются для набора DataColumns каждой таблицы DataTable. Чтобы просмотреть существующую проверку на уровне полей автоматически, перейдите к Designer DataSet, выберите поле из одной из строк DataTables и перейдите к окно свойств. Как показано на рисунке QuantityPerUnit 4, dataColumn в объекте ProductsDataTable имеет максимальную длину 20 символов и допускает NULL значения. Если попытаться задать ProductsDataRowQuantityPerUnit для свойства значение строки длиной более 20 символовArgumentException, будет выдано исключение .

DataColumn обеспечивает базовую проверку Field-Level

Рис. 4. DataColumn предоставляет базовую проверку Field-Level (щелкните для просмотра полноразмерного изображения)

К сожалению, мы не можем указать проверки границ, например UnitPrice значение должно быть больше или равно нулю, через окно свойств. Чтобы обеспечить этот тип проверки на уровне поля, необходимо создать обработчик событий для события ColumnChanging DataTable. Как упоминалось в предыдущем руководстве, объекты DataSet, DataTables и DataRow, созданные типизированным набором данных, можно расширить с помощью разделяемых классов. Используя этот метод, можно создать ColumnChanging обработчик событий для ProductsDataTable класса . Начните с создания класса в папке App_Code с именем ProductsDataTable.ColumnChanging.cs.

Добавление нового класса в папку App_Code

Рис. 5. Добавление нового класса в папку App_Code (щелкните для просмотра полноразмерного изображения)

Затем создайте обработчик событий для ColumnChanging события , который гарантирует, что UnitPriceзначения столбцов , UnitsInStock, UnitsOnOrderи ReorderLevel (если нет NULL) больше или равны нулю. Если какой-либо такой столбец выходит за пределы диапазона, создайте исключение ArgumentException.

ProductsDataTable.ColumnChanging.cs

public partial class Northwind
{
    public partial class ProductsDataTable
    {
        public override void BeginInit()
         {
            this.ColumnChanging += ValidateColumn;
         }

         void ValidateColumn(object sender,
           DataColumnChangeEventArgs e)
         {
            if(e.Column.Equals(this.UnitPriceColumn))
            {
               if(!Convert.IsDBNull(e.ProposedValue) &&
                  (decimal)e.ProposedValue < 0)
               {
                  throw new ArgumentException(
                      "UnitPrice cannot be less than zero", "UnitPrice");
               }
            }
            else if (e.Column.Equals(this.UnitsInStockColumn) ||
                     e.Column.Equals(this.UnitsOnOrderColumn) ||
                     e.Column.Equals(this.ReorderLevelColumn))
            {
                if (!Convert.IsDBNull(e.ProposedValue) &&
                    (short)e.ProposedValue < 0)
                {
                    throw new ArgumentException(string.Format(
                        "{0} cannot be less than zero", e.Column.ColumnName),
                        e.Column.ColumnName);
                }
            }
         }
    }
}

Шаг 4. Добавление пользовательских бизнес-правил в классы BLL

В дополнение к проверке на уровне полей могут существовать высокоуровневые пользовательские бизнес-правила, включающие различные сущности или понятия, не выразимые на уровне одного столбца, например:

  • Если продукт недоступен, его UnitPrice невозможно обновить
  • Страна проживания сотрудника должна совпадать со страной проживания руководителя
  • Продукт не может быть прекращен, если он является единственным продуктом, предоставляемым поставщиком

Классы BLL должны содержать проверки на соответствие бизнес-правилам приложения. Эти проверки можно добавить непосредственно в методы, к которым они применяются.

Представьте, что наши бизнес-правила предписывают, что продукт не может быть помечен как неподдерживаемый, если он был единственным продуктом от данного поставщика. То есть, если продукт X был единственным продуктом, который мы приобрели у поставщика Y, мы не могли бы пометить X как неподдерживаемый; Если же поставщик Y поставил нам три продукта: A, B и C, то мы могли бы пометить любой из них как неподдерживаемые. Нечетное бизнес-правило, но бизнес-правила и здравый смысл не всегда согласованы!

Чтобы применить это бизнес-правило в UpdateProducts методе , мы сначала проверим, было ли Discontinued задано значение true , и если да, мы вызовем GetProductsBySupplierID , чтобы определить, сколько продуктов мы приобрели у поставщика этого продукта. Если у этого поставщика приобретен только один продукт, мы выдаем исключение 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 is 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 it is 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;
}

Реагирование на ошибки проверки на уровне представления

При вызове BLL с уровня представления можно решить, следует ли обрабатывать любые исключения, которые могут быть вызваны, или разрешить их пузырьков до ASP.NET (что вызовет HttpApplicationError событие ). Чтобы обработать исключение при работе с BLL программным способом, можно использовать try... Блок catch , как показано в следующем примере:

ProductsBLL productLogic = new ProductsBLL();

// Update information for ProductID 1
try
{
    // This will fail since we are 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);
}

Как мы увидим в последующих руководствах, обработка исключений, которые возникают из BLL при использовании веб-элемента управления данными для вставки, обновления или удаления данных, может обрабатываться непосредственно в обработчике событий, а не упаковывать код в try...catch блоки.

Сводка

Хорошо спроектированное приложение состоит из отдельных слоев, каждый из которых инкапсулирует определенную роль. В первом руководстве этой серии статей мы создали уровень доступа к данным с помощью типизированных наборов данных. В этом руководстве мы создали уровень бизнес-логики в виде ряда классов в папке приложения App_Code , которые вызываются в DAL. BLL реализует логику уровня поля и бизнес-уровня для нашего приложения. В дополнение к созданию отдельного BLL, как мы делали в этом руководстве, еще один вариант — расширить методы TableAdapters за счет использования разделяемых классов. Однако использование этого метода не позволяет переопределить существующие методы и не разделяет DAL и BLL так же четко, как подход, используемый в этой статье.

После завершения DAL и BLL мы готовы начать работу с уровнем презентации. В следующем руководстве мы кратко рассмотрим разделы, посвященные доступу к данным, и определим согласованный макет страницы для использования в учебниках.

Счастливое программирование!

Об авторе

Скотт Митчелл (Scott Mitchell), автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с Веб-технологиями Майкрософт с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Sams Teach Yourself ASP.NET 2.0 в 24 часа. Его можно связать по адресу mitchell@4GuysFromRolla.com. или через его блог, который можно найти по адресу http://ScottOnWriting.NET.

Отдельная благодарность

Эта серия учебников была проверена многими полезными рецензентами. В этом руководстве были ведущие рецензенты Лиз Шулок( Liz Shulok), Деннис Паттерсон (Dennis Patterson), Карлос Сантос (Carlos Santos) и Hilton Giesenow (Хилтон Гисеноу). Хотите ознакомиться с моими предстоящими статьями MSDN? Если да, опустите мне строку в mitchell@4GuysFromRolla.com.