技术开发 频道

ASP.NET2.0:AdventureWorks贸易系统


【IT168技术文档】

    上一篇文章重点对AdventureWorks贸易系统的基本概况,数据库设计和CLR存储过程进行了讲解。本文主要说明该系统的数据访问层实现方法。 

1. 实现数据访问层

    本节将讲解数据访问层的实现,该层包括与AdventureWorks数据库通信的所有必要类和方法。首先,使用Visual Studio 2005创建新的Visual C#类库项目AdventureWorksTraderDataAccess。当这个项目创建后,可修改默认类名称为ProductCategoryDB。示例1说明了ProductCategoryDB类的实现代码。

    示例1:实现ProductCategoryDB类
using System; 
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Text;
using AdventureWorksTraderEntities;
using Microsoft.Practices.EnterpriseLibrary.Data;

namespace AdventureWorksTraderDataAccess
{
public class ProductCategoryDB
{
private DataColumnMapping[] mappings = new DataColumnMapping[] { new DataColumnMapping("ProductCategoryID", "ProductCategoryID"), new DataColumnMapping("Name", "Name"), new DataColumnMapping("rowguid", "Rowguid"), new DataColumnMapping("ModifiedDate", "ModifiedDate") };

public IList<ProductCategory> GetProductCategories()
{
IList<ProductCategory> list = new List<ProductCategory>();
Database db = DatabaseFactory.CreateDatabase();
string storedProcedureName = "GetProductCategories";
DbCommand dbCommand = db.GetStoredProcCommand(storedProcedureName);
using (IDataReader reader = db.ExecuteReader(dbCommand))
{
while (reader.Read())
{
ProductCategory temp = new ProductCategory();
ProductCategory category = (ProductCategory)DataAccessHelper.PopulateEntity(temp, mappings, reader);
list.Add(category);
}
}
return list;
}
}
}
    ProductCategoryDB类仅包括GetProductCategories方法,该方法返回ProductCategory表中包括的所有类别。在内部,GetProductCategories()方法利用EntLib数据访问块来执行GetProductCategories存储过程,接着将输出转换为由多个ProductCategory对象组成的泛型集合。GetProductCategories()方法中的构造块实现了如下功能:

    使用EntLib数据访问块实现数据访问
    使用泛型工具将输出转换为泛型集合
    实现ProductCategory项目
    使用泛型集合方式传送数据
    以下内容详细说明这些构建块。

 使用数据访问块实现数据访问


    ADO.NET提供了丰富的,能够以多种方式获取和显示数据的功能。即使使用ADO.NET提供的灵活性,但有时候开发人员仍然会发现自己一遍又一遍的在重复编写相同的代码。例如,每个数据驱动的应用程序都需要访问数据库,那么开发人员则要编写代码来连接数据库,打开数据库,执行SQL语句或者存储过程,在客户应用程序中获取结果,关闭数据库。开发人员将被迫在所开发的几乎任何应用程序中编写这些重复性代码,而这对于核心业务用户没有任何真正的价值。在开发的每个应用程序中可能唯一可能不同的代码是,SQL语句或者存储过程名称,命令参数和连接字符串。只要能够参数化这些变量,就能够将多数重复性代码抽象到可重用类中,那么在多个应用程序中都能够使用这些类。微软已经以EntLib数据访问块的形式完成了这件事。本实例将使用数据访问块来与数据库交流。

什么是数据访问块

    正如前文提到的,当开发数据库应用程序时,数据访问块用于完成开发人员所面对的多数常见任务。数据访问块通过提供一组封装的方法能够大大简化访问数据库的多数常见方法。每个方法都封装了实现返回数据所需的逻辑,同时,还能够管理数据库连接。另外,通过编写能够跨不同数据库类型使用,而不必修改代码的数据访问代码,数据访问块对ADO.NET 2.0提供了补充。这些类包括了提供给专用数据库实现功能(例如参数处理和游标)的代码。

    此外,数据访问块还为SQL Server和Oracle提供了专用的继承类。另外,GenericDatabase类还允许通过任何经过配置的ADO.NET 2.0中的DbProviderFactory对象使用应用程序块。开发人员通过添加实现新的包括专用数据库功能的数据库类型,或者提供了现有数据库的自定义实现来扩展应用程序块。

    数据访问块2.0版本较1.0斑斑有了革命性改进,其设计重新设计用于使用ADO.NET 2.0功能。开发人员可以从www.microsoft.com/downloads下载和查找EntLib数据访问块。

使用数据访问块的步骤

    为了使用数据访问块,需要执行以下步骤:
    1. 在解决方案中添加对Microsoft.Practices.EnterpriseLibrary.Common.dll和Microsoft.Practices.EnterpriseLibrary.Data.dll程序集的引用。使用添加应用选项,导航到<驱动器名称>:\Program Files\Microsoft Enterprise Library January 2006\bin文件夹中,可实现添加对这些程序集的引用。

    2. 在Web.config,app.config或者自定义配置文件中添加必要的配置项。为此,将以下<configSections>元素添加到<configuration>元素下:
<configSections>
<section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data" />
</configSections>
    3. 然后还要将<dataConfiguration>元素直接添加到<configuration>元素下,如下所示:
<dataConfiguration defaultDatabase=”AdventureWorksDB”/>
    4. 本实例将AdventureWorksDB数据库标记为默认数据库,其在<connectionStrings>元素中独立声明:
<connectionStrings> 
<add name="AdventureWorksDB" providerName="System.Data.SqlClient"
connectionString="server=localhost; database=AdventureWorks; UID=user; PWD=word; "/>
</connectionStrings>
    5. 在代码中导入数据访问块的核心命名空间Microsoft.Practices. EnterpriseLibrary.Data。
    6. 在核心命名空间下开始编写类代码。
    既然读者已经了解了EntLib数据访问块的基础知识,那么下面可以学习一下数据访问块中的关键类。

Database对象

    任何时候使用数据访问块,首先必须处理Database类。Database类表示数据库以及在数据库中执行命令的方法。Database对象公开了以下方法,使用这些方法能够对数据库执行CRUD操作。



    既然读者已经了解了Database类中的方法,那么就可以重新考虑数据访问层ProductCategory类的GetProductCategories()方法,以便理解集成数据访问块的方法:
IList<ProductCategory> list = new List<ProductCategory>(); 
Database db = DatabaseFactory.CreateDatabase();
string storedProcedureName = "GetProductCategories";
DbCommand dbCommand = db.GetStoredProcCommand(storedProcedureName);
using (IDataReader reader = db.ExecuteReader(dbCommand))
    首先,调用DatabseFactory类的CreateDatabase()方法以获取Database对象实例。正如名称暗示的那样,DatabaseFactory类包括了创建Database对象的工厂方法。注意,CreateDatabase()是一个重载方法,当调用无参数的CreateDatabase()方法时,该方法将返回默认数据库。为此,可在Web.config文件中,将defaultDatabase属性设置为适当的数据库配置键,如下所示:
<dataConfiguration defaultDatabase = "AdventureWorksDB" />
    当创建Database对象实例后,接着可调用GetStoredCommand()方法,以便生成ADO.NET 2.0的DBCommand对象。此后,将DbCommand作为参数传递给ExecuteReader()方法,并利用该方法执行存储过程。
使用泛型程序实现输出转换

    当获取了作为输出的SqlDataReader对象后,下一步是将输出内容转换为可发送到业务逻辑层的泛型集合。
GetProductCategories()方法利用辅助类DataAccessHelper(如示例2所示)将SqlDataReader对象内容转换为对象。

    示例2:实现DataAccessHelper类
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Data.Common;
using System.Reflection;
using System.Collections;

namespace AdventureWorksTraderDataAccess
{
public class DataAccessHelper
{
static public object PopulateEntity(object entity, DataColumnMapping[] mappings, IDataReader reader)
{
foreach (DataColumnMapping mapping in mappings)
{
int ordinalPosition = 0;
try
{
ordinalPosition = reader.GetOrdinal(mapping.SourceColumn);
}
catch (IndexOutOfRangeException ex)
{
throw new PropertyColumnMappingException(mapping.SourceColumn +
" is not a valid SourceColumn", ex);
}
object propertyValue = reader.GetValue(ordinalPosition);
if (propertyValue != DBNull.Value)
{
if (mapping.DataSetColumn == "ID")
{
Nullable<int> tempValue = (int)propertyValue;
propertyValue = tempValue;
}
object[] param = { propertyValue };
try
{
entity.GetType().InvokeMember(mapping.DataSetColumn, BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Static, null, entity, param);
}
catch (Exception e)
{
throw new PropertyColumnMappingException
(GetPropertyColumnMappingExceptionMessage(mapping), e);
}
}
}
return entity;
}

private static string GetPropertyColumnMappingExceptionMessage
(DataColumnMapping mapping)
{
return "Could not populate " + mapping.DataSetColumn +
" property from the " + mapping.SourceColumn + " database column";
}
}
}
    在GetProductCategories()方法内部,首先声明了一个DataColumnMapping数组,该数组中包括ProductCategory表列与ProductCategory对象属性之间的所有映射信息:
private DataColumnMapping[] mappings = new DataColumnMapping[] { 
new DataColumnMapping("ProductCategoryID", "ProductCategoryID"),
new DataColumnMapping("Name", "Name"),
new DataColumnMapping("rowguid", "Rowguid"),
new DataColumnMapping("ModifiedDate", "ModifiedDate")};
    当调用PopulateEntity()时,需要提供ProductCategory对象实例,DataColumnMapping数组以及包括执行存储过程所得输出的SqlDataReader对象:
ProductCategory category = (ProductCategory)DataAccessHelper.PopulateEntity(temp, mappings, reader);
    PopulateEntity()方法将SqlDataReader对象的每一行转换为具有适当属性值的ProductCategory对象。
4. 实现ProductCategory对象


    除了数据访问和业务逻辑层组件之外,本实例还包括另一个名为AdventureWorksTraderEntities的项目,该项目公开了一组直接对应数据库中实体的对象。ProductCategory表对应的是ProductCategory类(如示例3所示),该类可作为容器存储与ProductCategory有关的数据。

    示例3:实现ProductCategory类
using System; 
using System.Collections.Generic;
using System.Text;
namespace AdventureWorksTraderEntities
{
[Serializable]
public class ProductCategory
{
private int _productCategoryID;
private string _name;
private Guid _rowguid;
private DateTime _modifiedDate;

public int ProductCategoryID
{
get { return _productCategoryID; }
set { _productCategoryID = value; }
}

public string Name
{
get { return _name; }
set { _name = value; }
}

public Guid Rowguid
{
get { return _rowguid; }
set { _rowguid = value; }
}

public DateTime ModifiedDate
{
get { return _modifiedDate; }
set { _modifiedDate = value; }
}
}
}
    正如看到的,ProductCategory类如同一个占位符,每个属性都直接对应ProductCategory表中的一个列。

使用泛型集合

    读者应该记得GetProductCategories()方法的返回值,该值是ProductCategory对象的泛型集合。以下代码段专用于泛型集合:
while (reader.Read()) 
{
ProductCategory temp = new ProductCategory();
ProductCategory category = (ProductCategory)
DataAccessHelper.PopulateEntity(temp, mappings, reader);
list.Add(category);
}
    在以上代码中,首先,循环整个SqlDataReader对象,然后,将SqlDataReader对象的每一行都转换为一个ProductCategory对象,最后,将ProductCategory对象添加到泛型集合中。

    使用泛型可使得软件组件中的代码更加具有可重用性。泛型是一种数据结构类型,其中包含的代码保持不变。参数的数据类型能够在使用时变化。根据所提供的变量,使用数据结构能够适应不同的数据类型。每次使用泛型时,可自定义不同的数据类型,而无需重写任何内部代码。泛型允许类、结构、接口、委托和方法,将它们所存储和操作的数据类型实现参数化。

    在ASP.NET页面中,GetProductCategories()返回的泛型集合直接绑定到ObjectDataSource控件。当随后讲解本实例Web站点实现时将看到这些内容。

5. 实现ProductSubcategoryDB类

    ProductSubcategoryDB类包括GetProductSubcategories()方法,该方法根据产品类别返回所属所有子类别的列表。这个方法的实现非常类似于ProductCategory.GetProductCategories()。示例4列举了ProductSubcategoryDB类的实现代码。

    示例4:实现ProductSubcategoryDB类
using System;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Text;
using AdventureWorksTraderEntities;
using Microsoft.Practices.EnterpriseLibrary.Data;

namespace AdventureWorksTraderDataAccess
{
public class ProductSubcategoryDB
{
private DataColumnMapping[] mappings = new DataColumnMapping[] {
new DataColumnMapping("ProductSubcategoryID","ProductSubcategoryID"),
new DataColumnMapping("ProductCategoryID","ProductCategoryID"),
new DataColumnMapping("Name","Name"),
new DataColumnMapping("rowguid","Rowguid"),
new DataColumnMapping("ModifiedDate","ModifiedDate")};

public IList<ProductSubcategory> GetProductSubCategories(int productCategoryID)
{

IList<ProductSubcategory> list = new List<ProductSubcategory>();
Database db = DatabaseFactory.CreateDatabase();
string storedProcedureName = "GetProductSubcategories";
DbCommand dbCommand = db.GetStoredProcCommand(storedProcedureName);
db.AddInParameter(dbCommand, "productCategoryID", DbType.Int32, productCategoryID);
using (IDataReader reader = db.ExecuteReader(dbCommand))
{
while (reader.Read())
{
ProductSubcategory temp = new ProductSubcategory();
ProductSubcategory subCategory = (ProductSubcategory)DataAccessHelper.PopulateEntity(temp, mappings, reader);
list.Add(subCategory);
}
}
return list;
}
}
}
    正如在示例5看到的,GetProductSubcategories()方法执行了GetProductSubcategories存储过程。该存储过程接受productCategoryID参数。此后的实现与GetProductCategories()方法相同。
6. 实现ProductDB类

    正如名称暗示的那样,示例5所示的ProductDB类提供了专门访问AdventureWorks数据库中Product表的方法。该类包括一个GetProducts()方法,该方法根据提供的产品子类别ID返回所属的所有产品。

    示例5:实现ProdctDB类
using System; 
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Text;
using AdventureWorksTraderEntities;
using Microsoft.Practices.EnterpriseLibrary.Data;

namespace AdventureWorksTraderDataAccess
{
public class ProductDB
{
private DataColumnMapping[] mappings = new DataColumnMapping[] {
new DataColumnMapping("ProductID","ProductID"),
new DataColumnMapping("Name","Name"),
new DataColumnMapping("ProductNumber","ProductNumber"),
new DataColumnMapping("MakeFlag","MakeFlag"),
new DataColumnMapping("FinishedGoodsFlag","FinishedGoodsFlag"),
new DataColumnMapping("Color","Color"),
new DataColumnMapping("SafetyStockLevel","SafetyStockLevel"),
new DataColumnMapping("ReorderPoint","ReorderPoint"),
new DataColumnMapping("StandardCost","StandardCost"),
new DataColumnMapping("ListPrice","ListPrice"),
new DataColumnMapping("Size","Size"),
new DataColumnMapping("SizeUnitMeasureCode","SizeUnitMeasureCode"),
new DataColumnMapping("WeightUnitMeasureCode","WeightUnitMeasureCode"),
new DataColumnMapping("Weight","Weight"),
new DataColumnMapping("DaysToManufacture","DaysToManufacture"),
new DataColumnMapping("ProductLine","ProductLine"),
new DataColumnMapping("Class","Class"),
new DataColumnMapping("Style","Style"),
new DataColumnMapping("ProductSubcategoryID","ProductSubcategoryID"),
new DataColumnMapping("ProductModelID","ProductModelID"),
new DataColumnMapping("SellStartDate","SellStartDate"),
new DataColumnMapping("SellEndDate","SellEndDate"),
new DataColumnMapping("DiscontinuedDate","DiscontinuedDate"),
new DataColumnMapping("rowguid","Rowguid"),
new DataColumnMapping("ModifiedDate","ModifiedDate")};

public IList<Product> GetProducts(int productSubcategoryID)
{
IList<Product> list = new List<Product>();
Database db = DatabaseFactory.CreateDatabase();
string storedProcedureName = "GetProducts";
DbCommand dbCommand = db.GetStoredProcCommand(storedProcedureName);
db.AddInParameter(dbCommand, "productSubCategoryID", DbType.Int32,
productSubcategoryID);
using (IDataReader reader = db.ExecuteReader(dbCommand))
{
while (reader.Read())
{
Product temp = new Product();
Product prod = (Product)DataAccessHelper.PopulateEntity(temp, mappings, reader);
list.Add(prod);
}
}
return list;
}
}
}
    GetProducts()方法执行了GetProducts存储过程,该存储过程接受产品子类别ID作为参数,同时基于该产品子类别返回所属的所有产品列表。


7. 实现业务逻辑层

    本节将关注业务逻辑层的实现,该层封装在类库AdventureWorksTraderBiz中。首先,使用Visual Studio 2005,创建新的名为AdventureWorksTraderBiz的Visual C#类库项目。此后,添加上一节中创建的AdventureWorksTraderDataAccess的引用。一旦项目创建后,可将名为ProductCategoryBiz的类添加到项目中,接着如示例6所示修改代码。

    示例6:实现ProductCategoryBiz类

using System; 
using System.Collections.Generic;
using System.Text;
using AdventureWorksTraderEntities;
using AdventureWorksTraderDataAccess;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;

namespace AdventureWorksTraderBiz
{
public class ProductCategoryBiz
{
public IList<ProductCategory> GetProductCategories()
{
try
{
ProductCategoryDB category = new ProductCategoryDB();
return category.GetProductCategories();
}
catch (Exception ex)
{
bool rethrow = ExceptionPolicy.HandleException(ex, "Log Only Policy");
if (rethrow)
{
throw;
}
return null;
}
}
}
}
    示例6中所示的GetProductCategories()是主要方法,该方法通过调用数据访问层的GetProductCategories()方法来获取所需数据。业务逻辑层中生成的任何异常都在catch块中通过EntLib异常处理块处理。这是下一节关注的重要问题。

    由于业务逻辑层中剩余类(ProductSubcategoryBiz和ProductBiz)的实现与ProductCategoryBiz非常相似——除了它们调用的对应数据访问层类的方法不同——所以将不会详细讲解剩余类。然而,读者可从www.wrox.com下载本实例的完整代码。
8. 快速浏览企业库中的异常处理块

    开发人员编写的每个.NET应用程序都需要处理异常以及从异常中恢复。微软没有采取在.NET应用程序中创建,测试和维护传统代码的方法,而是创建了称为企业库异常处理块(或者称为EntLib异常处理块)的应用程序块。该应用程序块提供了实现异常处理所需的所有底层传统代码。为达成本实例的目的,将以统一高效的方式使用EntLib异常处理块处理异常。在讨论异常处理块与Web站点AdventureWorksTrader集成的所需步骤之前,读者需要理解异常处理块的基础知识。

异常处理块中的关键组件

    为理解异常处理块需要了解三个重要概念:

    异常处理:当在代码中检测到异常时,处理异常的过程。
    异常日志:记录异常的过程,该过程包括将格式化异常发送到事件日志或者发送电子邮件。异常处理块利用日志和监测应用程序块来实现此功能。
    异常处理策略:允许控制异常处理和使用外部配置文件记录的行为,而不用在代码中实施这样的规则。换句话说,开发人员可在一个策略文件中定义异常处理,然后在不改变代码的情况下,在测试、调试、产品定型期间修改行为。

    使用异常处理块,在代码中检测到异常时,可做以下三件事情:

    第一,可把异常封装为一个新的异常,以便加入新的上下文信息或详细信息。当新的异常传递到调用堆栈时,仍可通过InnerException属性访问原始的异常。
    第二,可用一个新的异常取代原有异常。通常,这样做的目的是不想让原始异常的详细信息跨应用程序边界传递。
    第三,能够记录异常。当然,也可结合使用封装或取代的方法达成此目的,或者记录原始异常并把它传递到调用堆栈。

使用异常处理块


    通过浏览www.microsoft.com/downloads和查找EntLib,开发人员可下载EntLib缓存块,其中包括了异常处理块。在安装完企业库之后,就可利用异常处理块开始编写代码。为正确使用异常处理块,需要遵循以下步骤:

    1. 在解决方案中分别添加对Microsoft.Practices.EnterpriseLibrary.Common.dll和Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.dll程序集的引用,为此,可使用“添加引用”选项,并定位到<驱动程序名>:\Program Files\Microsoft Enterprise Library January 2006\bin文件夹。如果还需要结合异常处理使用日志记录,则再添加对Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.dll的引用。

    2. 在app.config或者Web.config文件中添加必要的配置项。为此,可在根<configuration>元素下的<configSections>元素中添加如下内容:
<section name="exceptionHandling" 
type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.
Configuration.ExceptionHandlingSettings,Microsoft.Practices.
EnterpriseLibrary.ExceptionHandling" />
    3. 如果随同异常处理一起使用日志记录,则还需要在<configSections>元素中添加以下设置:
<section name="loggingConfiguration"
type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.
LoggingSettings,Microsoft.Practices.EnterpriseLibrary.Logging" />
    4. 接下来,直接在<configuration>元素下添加<exceptionHandling>元素。在<exceptionHandling>内部可添加所有的异常处理策略。以下代码说明在<exceptionHandling>中指定了一个名为“Global Policy”的策略。
<exceptionHandling> 
<exceptionPolicies>
<add name="Log Only Policy">
<exceptionTypes>
<add name="Exception" type="System.Exception, mscorlib,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction="ThrowNewException">
<exceptionHandlers>
<add logCategory="Default Category" eventId="100" severity="Error"
title="Exception Management Application Exception" priority="0"
formatterType="Microsoft.Practices.EnterpriseLibrary.
ExceptionHandling.TextExceptionFormatter,
Microsoft.Practices.EnterpriseLibrary.ExceptionHandling"
name="Logging Handler"
type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.
Logging.LoggingExceptionHandler,
Microsoft.Practices.EnterpriseLibrary.
ExceptionHandling.Logging"/>
</exceptionHandlers>
</add>
</exceptionTypes>
</add>
</exceptionPolicies>
</exceptionHandling>
    5. 正如这些设置所指示的那样,有一个名为Log Only Policy的策略,该策略能够记录异常。使用<exceptionHandlers>节能够设置以适当方式处理异常的自定义异常处理程序。在这种情况下,自定义处理程序实现LoggingExceptionHandler类。postHandlingAction属性用于根据策略设置异常处理之后的行为。该属性包括以下可能值:None,NotifyRethrow和ThrowNewException。

    6. 在代码中导入异常处理块的核心命名空间Microsoft.Practices.EnterpriseLibrary.ExceptionHandling。

    7. 开始使用上述命名空间中的类编写代码。

ExceptionPolicy对象

    只要使用异常处理块,就必须处理ExceptionPolicy类。ExceptionPolicy类公开了静态方法HandleException(),利用该方法可使客户端应用程序与异常处理块交互,此时将策略作为参数提供。HandleException()方法使用类工厂来为相应的策略创建ExceptionPolicyImpl类型的对象。ExceptionPolicyImpl对象具有一个ExceptionPolicyEntry对象集合。在名为策略的配置文件中,每种异常类型都对应一个对象。对每一种异常类型,ExceptionPolicyEntry对象都包含一个实现IExceptionHandler接口的对象集合。当执行策略时,对象集合能够提供异常处理块使用的序列。每个实现IExceptionHandler接口的对象都与对应处理方法的类型相关联。

    异常处理方法是 .NET类,其封装了异常处理逻辑,并实现了定义在异常处理块中的IExceptionHandler接口。默认情况下,异常处理块包含以下三种异常处理程序:

    封装处理程序:此异常处理程序使用一个异常封装另一个异常
    取代处理程序:此异常处理程序用一个异常取代另一个异常
    日志记录处理程序:此异常处理程序对异常信息进行格式化处理,例如,消息和堆栈跟踪。然后日志记录处理方法将这些信息记录到日志块,以作日后查证。

    既然已经了解了异常处理块的基础知识,下面将重新讲解业务逻辑层类的代码,以便理解异常处理块的集成:
public IList<ProductCategory> GetProductCategories()
{
try
{
ProductCategoryDB category = new ProductCategoryDB();
return category.GetProductCategories();
}
catch (Exception ex)
{
bool rethrow = ExceptionPolicy.HandleException(ex, "Log Only Policy");
if (rethrow)
{
throw;
}
return null;
}
}
    在try块中无论何时发生异常,都将在catch块中捕获异常,并在其中调用ExceptionPolicy对象的HandleException()方法,以便记录异常。在记录异常之后,可查看HandleException()方法的返回值(根据配置文件中的postHandlingAction属性),以便确定是否需要向调用者抛出异常。

9. 小结

   本文介绍的数据访问层实现中涉及集成重用块,开发人员使用这些块能够快速方便的实现数据访问、异常处理等很多重复性高的任务。建议读者在学习这些重用块之后,将其应用到自身的项目开发过程中,从而提高开发效率。
下一篇文章讲解Web站点部分的实现方法。
0
相关文章