Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом руководстве мы посмотрим, как централизировать бизнес-правила на уровне бизнес-логики (BLL), который служит посредником для обмена данными между уровнем презентации и DAL.
Введение
Уровень доступа к данным (DAL), созданный в первом руководстве , четко отделяет логику доступа к данным от логики презентации. Однако, хотя DAL чисто отделяет сведения о доступе к данным от слоя презентации, он не применяет какие-либо бизнес-правила, которые могут применяться. Например, для нашего приложения может потребоваться запретить изменение полей CategoryID
или SupplierID
в таблице Products
, если для поля Discontinued
задано значение 1, или нам может потребоваться применить правила иерархии, запрещая ситуации, когда сотрудником управляет тот, кто был нанят позже него. Другой распространенный сценарий — авторизация, возможно, только пользователи определенной роли могут удалять продукты или изменять UnitPrice
значение.
В этом руководстве мы посмотрим, как централизировать эти бизнес-правила в уровне бизнес-логики (BLL), который служит посредником для обмена данными между уровнем презентации и DAL. В реальном приложении BLL следует реализовать как отдельный проект библиотеки классов; Однако для этих учебников мы реализуем BLL в виде ряда классов в нашей App_Code
папке, чтобы упростить структуру проекта. Рисунок 1 иллюстрирует архитектурные связи между уровнем презентации, BLL и DAL.
Рис. 1. BLL отделяет уровень презентации от уровня доступа к данным и накладывает бизнес-правила
Шаг 1. Создание классов BLL
Наш BLL будет состоять из четырех классов, по одному для каждого TableAdapter в DAL; каждый из этих классов BLL будет иметь методы для получения, вставки, обновления и удаления из соответствующего TableAdapter в DAL, применяя соответствующие бизнес-правила.
Чтобы более четко разделить классы, связанные с DAL и BLL, давайте создадим две вложенные папки в папке App_Code
DAL
и BLL
. Щелкните правой кнопкой мыши App_Code
папку в обозревателе решений и выберите команду "Создать папку". После создания этих двух папок переместите типизированный набор данных, созданный в первом руководстве, в вложенную папку DAL
.
Затем создайте четыре файла класса BLL в подпапке BLL
. Чтобы это сделать, щелкните правой кнопкой мыши на BLL
подпапке, выберите "Добавить новый элемент" и выберите шаблон класса. Назовите четыре класса ProductsBLL
, CategoriesBLL
и SuppliersBLL
EmployeesBLL
.
Рис. 2. Добавление четырех новых классов в папку App_Code
Далее давайте добавим методы к каждому из классов, чтобы просто упаковать методы, определенные для TableAdapters из первого руководства. Сейчас эти методы будут просто вызываться непосредственно в DAL; мы позже добавим необходимую бизнес-логику.
Замечание
Если вы используете Visual Studio Standard Edition или более поздней версии (т. е. вы не используете Visual Web Developer), вы можете при необходимости визуально разработать классы с помощью конструктора классов. Дополнительные сведения об этой новой функции в Visual Studio см. в блоге конструктора классов .
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. Хотя в некоторых сценариях могут быть бизнес-правила, которые должны быть реализованы на этом уровне (например, правила авторизации на основе текущего пользователя или роли, к которой принадлежит пользователь), мы просто оставим эти методы as-is. Для этих методов BLL служит лишь прокси-сервером, через который слой презентации обращается к базовым данным из уровня доступа к данным.
Методы AddProduct
и UpdateProduct
принимают в качестве параметров значения для различных полей продукта и соответственно добавляют новый продукт или обновляют существующий. Так как многие из Product
столбцов таблицы могут принимать NULL
значения (CategoryID
, SupplierID
и UnitPrice
, чтобы назвать несколько), те входные параметры для AddProduct
и UpdateProduct
, которые соответствуют таким столбцам, используют типы, допускающие значение NULL. Типы, допускающие значение NULL, появились в .NET 2.0 и предоставляют способ указать, должен ли тип значения вместо этого быть null
. В C# можно пометить тип значения как тип, допускающий значение NULL, добавив ?
после типа (например int? x;
). Дополнительные сведения см. в разделе "Типы, допускающие значение NULL " в руководстве по программированию на C# .
Все три метода возвращают логическое значение, указывающее, была ли строка вставлена, обновлена или удалена, так как операция не может привести к затронутой строке. Например, если разработчик страницы вызывает DeleteProduct
, передавая ProductID
для несуществующего продукта, DELETE
SQL-запрос, отправленный в базу данных, не повлияет, и поэтому метод DeleteProduct
вернет false
.
Заметьте, что при добавлении нового продукта или обновлении существующего мы принимаем значения полей нового или измененного продукта в виде списка скаляров, а не экземпляра 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 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
. Этот метод предоставляет интерфейс для обновления только сведений об адресе поставщика.
SupplierDataRow
считывается этим методом для указанного supplierID
(с помощью GetSupplierBySupplierID
), задаются его свойства, связанные с адресом, а затем он вызывает метод SupplierDataTable
объекта Update
. Метод 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 более подробно в рамках следующих руководств.
Рис. 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
s. Четыре ограничения существуют, чтобы гарантировать, что только значения, превышающие или равные нулю, могут попасть в столбцы UnitPrice
, UnitsInStock
, UnitsOnOrder
или ReorderLevel
.
Помимо применения этих правил в базе данных, они также должны быть применены на уровне Набора данных. Фактически, длина поля, а также требуемость или необязательность значения уже зафиксированы для каждого набора DataColumns таблицы данных (DataTable). Чтобы просмотреть автоматическую проверку на уровне поля, перейдите в конструктор наборов данных, выберите поле из одной из наборов данных, а затем перейдите в окно "Свойства". Как показано на рисунке 4, QuantityPerUnit
DataColumn в ProductsDataTable
имеет максимальную длину 20 символов и допускает NULL
значения. Если мы попытаемся установить для ProductsDataRow
QuantityPerUnit
строковое значение длиной более 20 символов, будет выдано исключение ArgumentException
.
Рис. 4: DataColumn предоставляет базовую проверку Field-Level (нажмите, чтобы увеличить изображение)
К сожалению, невозможно указать проверки границ, например UnitPrice
значение должно быть больше нуля или равно нулю в окне "Свойства". Чтобы предоставить этот тип проверки на уровне поля, необходимо создать обработчик событий для события ColumnChanging dataTable. Как упоминалось в предыдущем руководстве, объекты DataSet, DataTables и DataRow, созданные типизированным набором данных, можно расширить с помощью частичных классов. С помощью этого метода можно создать ColumnChanging
обработчик событий для ProductsDataTable
класса. Начните с создания класса в папке App_Code
с именем ProductsDataTable.ColumnChanging.cs
.
Рис. 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 (что приведет к возникновению события HttpApplication
Error
). Чтобы обрабатывать исключение при работе с 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 мы готовы начать работу на нашем уровне презентации. В следующем руководстве мы рассмотрим краткий переход из разделов доступа к данным и определим согласованный макет страницы для использования во всех руководствах.
Счастливое программирование!
Сведения о авторе
Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга — Sams Teach Yourself ASP.NET 2.0 за 24 часа. С ним можно связаться по адресу mitchell@4GuysFromRolla.com.
Особое спасибо кому
Эта серия учебников была проверена многими полезными рецензентами. Ведущими рецензентами этого учебника были Лиз Шулок, Деннис Паттерсон, Карлос Сантос и Хилтон Гизенау. Хотите просмотреть мои предстоящие статьи MSDN? Если да, напишите мне на mitchell@4GuysFromRolla.com.