Создание уровня бизнес-логики (C#)
В этом руководстве мы посмотрим, как централизовать бизнес-правила в уровне бизнес-логики (BLL), который служит посредником для обмена данными между уровнем представления и DAL.
Введение
Уровень доступа к данным (DAL), созданный в первом руководстве , четко отделяет логику доступа к данным от логики представления. Однако, хотя DAL четко отделяет сведения о доступе к данным от уровня представления, он не применяет бизнес-правила, которые могут применяться. Например, для нашего приложения может потребоваться запретить CategoryID
изменение полей Products
или таблицыSupplierID
, если 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), при необходимости можно создать классы визуально с помощью 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
), задает его свойства, связанные с адресом, а затем вызывает 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
ли столбец таблицы базы данных значения . Существуют четыре ограничения проверка, которые гарантируют, что только значения, превышающие или равные нулю, могут попасть в UnitPrice
столбцы , UnitsInStock
, UnitsOnOrder
или ReorderLevel
.
Помимо применения этих правил в базе данных, они также должны применяться на уровне DataSet. На самом деле длина поля и то, является ли значение обязательным или необязательным, уже фиксируются для набора DataColumns каждой таблицы DataTable. Чтобы просмотреть существующую проверку на уровне полей автоматически, перейдите к Designer DataSet, выберите поле из одной из строк DataTables и перейдите к окно свойств. Как показано на рисунке QuantityPerUnit
4, 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 мы готовы начать работу с уровнем презентации. В следующем руководстве мы кратко рассмотрим разделы, посвященные доступу к данным, и определим согласованный макет страницы для использования в учебниках.
Счастливое программирование!
Об авторе
Скотт Митчелл (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.