Pet shop的设计模式与体系结构

本文介绍.NETPetShop3.x的设计模式与体系结构,详细阐述了从2.0到3.0版本的改进,包括引入数据库访问层、实现工厂模式以支持多种数据库平台,并优化了缓存机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:http://msdn.microsoft.com/zh-cn/library/ms954623.aspx

Microsoft .NET Pet Shop 3.x: .NET Pet Shop 的设计模式与体系结构
发布日期 : 4/1/2004 | 更新日期 : 4/1/2004

Gregory Leake Microsoft Corporation

James Duff Vertigo Software, Inc.

2003 年 5 月

适用于:

Microsoft? .NET 框架 1.0 和 1.1 Microsoft? Windows 2000 和 Windows Server? 2003 Microsoft? Internet Information Services Microsoft? SQL Server? 2000 Oracle? 9i Database

摘要:.NET Pet Shop 3.x 版针对 .NET Pet Shop 2.0 的评论者给出的重要反馈进行了改进,开发时确保了应用程序与 Microsoft 提出的体系结构指导文档保持一致。(20 页打印页)

下载 Pet Shop 3.0 Installer.msi 代码示例.

本页内容

摘要 摘要
Java Pet Store 是 什么? Java Pet Store 是 什么?
Microsoft .NET Pet Shop Microsoft .NET Pet Shop
业务需求 业务需求
应用程序数据模型 应用程序数据模型
.NET Pet Shop 2.0 体系结构 .NET Pet Shop 2.0 体系结构
.NET Pet Shop 3.0 体系结构 .NET Pet Shop 3.0 体系结构
小结 小结
附录 A: 从版本 2 到版本 3 的更改 附录 A: 从版本 2 到版本 3 的更改

摘要

最 初研究 .NET Pet Shop 的目的是用 Microsoft .NET 实现 Sun 主要的 J2EE 蓝图应用程序 Sun Java Pet Store 同样的应用程序功能。 根据用 .NET 实现的 Sun J2EE 最佳实践示例应用程序,各方面的客户可以直接地对 Microsoft 的 .NET 技术与基于 J2EE 的应用程序服务器进行比较,同时了解构建基于Web的应用程序中用到的各种建议的设计模式之间的异同。 .NET Pet Shop 应用程序现在已经是第三版了,旨在显示构建企业级 n 层应用程序(可能需要支持多种数据库平台和部署模型)的 .NET 最佳实践。 根据社区对 .Net Pet Shop 2.0 的反馈,.NET Pet Shop 3.0 遵照 MSDN 上发布的 Microsoft《说明性体系结构指导》进行了重新设计。 第三版还完全符合了 Middleware 公司的应用程序服务器基准测试规范,将作为 Microsoft 参加今年春天即将进行的 Middleware Application Server Benchmark 的产品: 这是Middleware 公司举办的第二轮测试活动,旨在比较 .NET 和 J2EE 平台在构建和承载企业级 Web 应用程序方面的可伸缩性。

Java Pet Store 是 什么?

Java Pet Store 是按 Sun 公司维护的 J2EE 蓝图开发的分布式应用程序的一个参考实现。 示例应用程序最初的开发目的是帮助开发人员和架构师理解如何使用和利用 J2EE 技术,以及各个 J2EE 平台组件是如何配合的。 Java Pet Store 演示软件包括构建应用程序所需的Enterprise Java Beans (EJB) 体系结构、 Java Server Pages (JSP) 技术、标记库和 servlet 的完整的源代码及文档。 此外, Java Pet Store 蓝图应用程序还通过具体示例说明了一些模型和设计模式。

完整的 Java Pet Store 包括三个示例应用程序:

  • Java Pet Store: J2EE 蓝图主应用程序。

  • Java Pet Store 管理器: Java Pet Store 的管理器模块

  • Blueprints Mailer: 在小一些的包中给出一些 J2EE 蓝图设计指南的一个小应用程序。

Java Pet Store 的最初版本旨在处理以下数据库: Oracle、Sybase 和Cloudscape 。 IBM 已经开发了一个 DB2 版本的应用程序。 该应用程序可以从 Java 2 Platform Enterprise Edition Blueprints 公开获得。 主应用程序 Java Pet Store 是一个电子商务应用程序,可以通过它在线购买宠物。 启动应用程序后,可以浏览和搜索各种类型的宠物,从狗到爬行动物。

使用 Java Pet Store 的典型会话方案如下:

主页 — 这是用户第一次启动应用程序时加载的主页。

类别查看 — 有五大类: 鱼、狗、爬行动物、猫和鸟。 每一类都有几个相关的产品。 如果选择鱼作为类别,可以看到天使鱼等等内容。

产品 — 如果现在选择一个产品,应用程序将显示产品的所有类型。 通常产品类型是雄或者雌。

产品详情 — 每种产品类型(分别用不同项目表示)有详细的视图显示产品说明、产品图像、价格和库存数量。

购物车 — 用户可以通过它操作购物车(添加、删除和更新行项目)。

结帐 — 结帐页面以只读视图显示购物车。

登录重定向 — 当用户选择结帐页面上的“Continue”时,如果还没有登录,将重定向到登录页面。

登录验证 — 通过站点的身份验证以后,用户被重定向到信用卡和记帐地址表单。

定单确认 — 显示记帐地址和送货地址。

定单提交 — 这是定单处理流程的最后一步。 定单现在将提交到数据库。

图 1. Java Pet Store

Microsoft .NET Pet Shop

.NET Pet Shop 的目标是把注意力仅仅放在 Java Pet Store 上(管理和Mailer 组件没有在 .NET 中实现)。 除了重现 Java Pet Store 应用程序的功能之外,还增加了两项目标:

  • 比较 .NET 和 J2EE 通过最佳实践实现的真实应用程序中代码和代码大小上的异同。

  • 提供用 .NET 和 J2EE 实现的典型的设计良好的应用程序能够支持多少用户的数据。

图 2. .NET Pet Shop

.NET Pet Shop 的整体逻辑体系结构如图 3 所示,设计的中心是在表示层使用 ASP.NET Web 窗体,与逻辑中间层中的 C# 业务组件通信。 业务组件继而通过 ADO.NET 和 SQL Server 名为数据访问应用块 (DAAB) (可 以从此链接了解更多 DAAB 信息并下载完整的 DAAB 源代码)的帮助器类访问后端数据库。 数据访问功能完全抽象到数据访问层 (DAL) 中,与业务逻辑层 (BLL) 相分离。 .NET Pet Shop 3.0 中的新颖之处在于,我们为 Oracle 9i 和 SQL Server 2000 数据库都引入了 DAL 层。 相应 DAL 层的类加载将根据 Web.Config 中的应用程序配置设置在运行时动态生成。注意 .NET Pet Shop 3.0 使用了两个后端数据库,定单处理中要涉及跨两个数据库的分布式事务。 使用简单的 Web.Config 应用程序设置,用户可以对 .Net Pet Shop 进行部署,使用一个或者多个后端数据库,还可以自由地将 SQL Server 和 Oracle 后端数据库与由 .NET 服务的组件通过 COM+ 企业服务处理的分布式事务混合。

图 3. .NET Pet Shop 高层逻辑体系结构

图 4 说明了 Microsoft .NET Pet Shop 物理上是怎样部署的。 这里使用网络负载平衡 (NLB) 或者可能是硬件实现的负载平衡技术将入站的网络通信量分到了两台应用程序服务器上。 在网络请求达到群集中的一台机器时,针对该请求的所有工作都会在这台特定机器上进行。 业务逻辑和数据访问组件将以程序集的形式安装在两台服务器上,它们本质上是完全相同的。 如果负载平衡软件配置为使用“Sticky IP”,则每台服务器都有自己的会话-状态存储,因为要保证第二个请求返回到实现第一个请求的那台服务器。 如果解决方案所需的容错要求更高,两台应用程序服务器可以共享一个公共会话-状态存储比如 SQL Server 或者一台专用的会话服务器(图中没有显示)。 会话-状态存储的类型和位置由每个站点‘web.config’文件里‘system.web’元素‘sessionState’子节点中的值决定。

图 4. .NET Pet Shop 的物理部署图

业务需求

作为 Pet Shop 3 体系结构文档的一部分,我们给出了 .NET Pet Shop 的业务需求,这样开发人员和客户就可以理解我们在做应用程序的设计决策时进行的一些选择。

Pet Shop 应用程序的功能性需求是什么?

  • 应用程序应该使客户能够按类和通过关键字搜索浏览公司目录。

  • 应用程序应该为客户提供一种通过一个购物车模型就能购买多个商品项的机制。

  • 应用程序应该提供简单的安全模型,这样客户必须先进行登录,才允许购买购物车的内容。

  • 应用程序旨在支持高容量的企业级电子商务解决方案;因此应用程序应该展示以下方面:

  • 高性能,通过所支持用户数和用户响应时间进行衡量

  • 通过增加更多处理器来扩展的能力

  • 通过增加更多机器组成群集的分布式扩展能力

  • 在大型企业级系统中,应用程序可能需要访问多个数据库,因此应用程序应该支持分布式事务。

  • 应 用程序应该考虑灵活的部署策略。 默认时应用程序的设计方案是要部署到两台机器上,一台是应用程序服务器,一台是数据库服务器,但是应该能够扩展在其他部署模型下工作。 应用程序应该支持多个数据库供应商。 这里我们选择了 Microsoft SQL Server 和Oracle。

  • 应用程序应该容易维护,这是通过应用程序中的代码行数来衡量的。

应用程序数据模型

.NET Pet Shop 中使用的数据库架构是直接从 Java Pet Store 移植而来的。 Java Pet Store 支持几种数据库供应商格式,因此我们选取了 Sybase 应用程序的架构,并在一个 Microsoft SQL Server 2000 实例中创建。 这不需要改变 Sybase 版本的架构。 而创建 Oracle 版本的 .NET Pet Shop 时,我们直接采用了 Java Pet Store 数据库原来的 Oracle 实现。

数据库 有如下整体表结构,参见表 1:

表 1. Pet Shop 中的数据库表

表名

用途

Account

代表基本客户信息

BannerData

存储广告条信息

Category

目录类别( Fish, Dogs, Cats 等)

Inventory

产品库存状态

Item

各个产品的细节

LineItem

定单细节

Orders

客户下的定单。 定单包括一个或多个行项目

OrderStatus

定单状态

Product

目录产品,每个产品可有一或多类型(项目)。 通常类型可能是雄或雌。

Profile

客户的用户配置情况

Signon

客户登录表

Supplier

有关供应商信息

在 .NET Pet Shop 版本 2 中,应用程序改为要创建一个方案,其中完成定单处理必须使用分布式事务。 为了适应分布式事务方案,Orders、OrderStatus 和 LineItem 表都分到不同的可能安装在不同机器上的数据库实例。 我们在 .NET Pet Shop 的第三版中保持了这个分布式设计模式。

图 5. .NET Pet Shop 订购数据库架构

图 6. .NET Pet Shop 帐号和产品数据库架构

Pet Shop 表的设计可以做什么更改?

应用程序中使用的架构可以做一些更改;然而,这些更改并不是为了与 Java Pet Store 参考实现提供的架构一致。 这些更改已列于表 2 中:

表 2. Pet Shop架构中可能的改进

更改

原因

表中不存储 HTML

因为可能要使用不同客户端应用程序类型,数据库仅存储图像文件名而不是图像标记,部署客户端类型可以更灵活。

对客户密码使用单向加密算法

帮助使应用程序更安全,因为即使系统任何部分的安全受到威胁,读取密码仍然很困难。 这是要求设施必须重置密码为新值。

加密信用卡信息

在系统安全受到威胁时防治对信用卡信息的访问。 做出的其他更改还有将表设为只能允许通过一个存储过程进行写入访问;因此黑客访问数据库将不得不需要另一套凭据来读取数据。

.NET Pet Shop 2.0 体系结构

图 7. .NET Pet Shop 2 应用程序的体系结构

.NET Pet Shop 2.0 被设计成部署在物理上两层的部署环境中,并且在应用程序的一些部分的实现中利用了这一事实。 应用程序由以下部分构成:一个用 ASP.NET Web 窗体 (用“代码隐藏”将应用程序 HTML 和用户接口代码分离)创建的 Web 层。 一个包含控制应用程序逻辑的业务组件(通过自定义版本的 Microsoft 数据库访问应用程序块 (DAAB) 与 SQL Server 数据库通信)的中间层。 为了支持分布式事务,一些中间层业务组件是用企业服务实现的。 对于 Microsoft .NET,这是一种支持分布式事务的建议方式。 然而,并非所有类都要扩展 ServicedComponent 类,因为将所有类都实现为企业服务的组件是有性能开销的。 发布第一次 Middleware 应用程序服务器基准测试中使用的 .NET Pet Shop 2.0 时,我们收到了许多反馈,认为体系结构应该优化,以更适应于大规模的企业。 反馈比较集中的方面包括:

  • 创建完全抽象的数据层,无需在中间层导入数据特定的类。

  • 为 Oracle 实现数据访问层,可以透明地使用与 SQL Server 版本一样的业务层和 UI 层。

  • 将 Web 会话状态从业务逻辑层和数据层中完全提取出来,这样应用程序的后端组件可以在物理上分布到 Web 服务器之外的其他计算机上,或者从其他类型的客户端比如基于 Windows的客户端和基于 Web– 的客户端重用。

  • 将应用程序模块整个分为多个命名空间和物理程序集。

  • 其他各方面的反馈。

.NET Pet Shop 3.0 体系结构

图 8. .NET Pet Shop 3.0 应用程序体系结构

应用领域

表 3. Pet Shop 解决方案中的应用领域

范围

用途

.NET 实现

用户接口组件

捕获来自用户的数据输入,显示后端系统返回的数据。 它们还处理简单的定位。 参见用户接口组件。

ASP.NET Web 窗体,用户控件和服务器控件。 这些构造能够清晰地分离设计者的 HTML 和 UI 代码比如按钮的事件处理程序。

用户接口处理

用后端业务对象控制用户定位和处理流程。 还要处理用户会话数据的管理。 参考用户处理组件。

这些是用 C# 类实现的。 会话状态管理由 ASP.NET 处理。

业务组件

实现应用程序业务逻辑的组件

这些是用 C# 类实现的

业务实体

在应用程序各层之间传递数据的瘦数据类。 参见业务实体组件。

这些是用 C# 类实现的,每个字段都以属性的形式公开。 每个类都标记为“serializable”,启用进程间传输。

数据访问层组件

处理与后端数据存储区的交互,包括数据库、消息处理系统等。

这些组件处理与后端数据存储区的交互,包括数据库、消息处理系统等,是用四个 C# 项目实现的:

 

 

  • 一组接口类,要公开的每个数据访问方法都有。

  • SQL Server 接口的实现。

  • Oracle 9i 接口的实现。

  • 一组加载正确实现的工厂类, SQL Server 或 Oracle。

Microsoft Visual Studio .NET 解决方案

图 9 显示了 Microsoft Visual Studio .NET 解决方案对 .NET Pet Shop 应用程序的布局。 应用程序的每个元素或层都有自己的项目,这样解决方案可以管理和清晰地定义应用程序中使用的新类应该放在哪里,旧类又可以在哪里找到。

图 9. Visual Studio .NET 应用程序解决方案

表 4 中列出了每个项目的目的:

表 4. Pet Shop 解决方案中的 Visual Studio 项目

项目

用途

BLL

业务逻辑组件存放之处

ConfigTool

用来加密连接字符串和创建事件日志源的管理应用程序

DALFactory

用来确定加载哪一个数据库访问程序集的类

IDAL

每个 DAL 实现都要实现的一组接口

Model

瘦数据类或业务实体

OracleDAL

Oracle 特定的 Pet Shop DAL 实现,使用了 IDAL 接口

Post-Build

运行编译后操作的项目,比如将程序集添加到 GAC 或 COM+

Pre-Build

将程序集从 GAC 删除或从 COM+ 注销程序集的项目

SQLServerDAL

Microsoft SQL Server 特定的 Pet Shop DAL 实现,使用了 IDAL 接口

Utility

一组帮助器类,包括 DPAPI 的包装

Web

Web 页和控件

Solution Items

用来构建应用程序的杂项,比如用来签署应用程序程序集的 Pet Shop.snk 密钥文件

数据库可移植性

这 一版本 Microsoft .NET Pet Shop 的关键需求之一是提供支持 Oracle 和 SQL Server 数据库的应用程序实现。 在设计应用程序的数据库访问机制时,我们可以选择应该使用哪一个数据库提供程序;可以使用通用的 OLE-DB 托管提供程序或者数据库特定的优化了性能的 .NET 托管提供程序,比如 .NET 框架1.1 中提供的 SQL Server 和 Oracle 托管提供程序。 应用程序的关键需求之一是创建一个高性能的解决方案,因此我们选择用数据库本身的 .NET 托管提供程序构建应用程序。 关于托管提供程序和通用 OLE-DB 提供程序之间的性能差异分析,读者可以参考 Using .NET Framework Data Provider for Oracle to Improve .NET Application Performance, 该文档说明了厂商特定的提供程序能够比等价的 OLE-DB 提供程序性能好两到三倍。 在选择数据库特定的访问类时进行的考虑是,我们需要为每个要支持的数据库平台写一个单独的数据访问层,因此应用程序将包含更多代码。 虽然两个数据访问层共享很多公共代码,但还是要明显地分别针对具体数据库(Oracle 或 SQL Server 2000)。

为了简 化数据库访问类的使用,我们选择 GoF (译注:指 Erich Gamma 等著《设计模式》一书)概述的工厂设计模式,通过反射动态在运行时加载正确的数据访问对象。 工厂设计模式是这样实现的: 创建一个 C# 接口,其中对于数据库访问类必须公开的每个方法都要声明一个方法。 对于每一个要支持的数据库,都创建一个实现数据库特定代码的具体类,以执行接口也称“协定”中的每一项操作。 为了支持运行时确定加载哪一个具体类,需要创建第三个类,也就是工厂类,它从配置文件中读入一个值以确定应该使用反射加载哪一个程序集。 通过 .NET 的反射命名空间,可以加载某个特定程序集并用该程序集创建某个对象的实例。 为了使应用程序更安全,为版本控制提供更好的支持,我们可以在应用程序配置文件(也就是这里的 web.config. )中添加要加载的程序集文件的“证据”,这意味着 .NET 框架将只加载我们在编译期间签过名而且有正确版本号的程序集。 图 10 说明了业务逻辑类、工厂类和数据库访问类是如何相互操作的。 这一创建的解决方案最重要的优势是数据库访问类可以在业务逻辑类之后编译,只要数据访问类实现了 IDAL 接口。 这意味着,如果要创建应用程序的 DB2 版本,我们不需要改动业务逻辑层(或者 UI 层)。 创建 DB2 兼容版本的步骤如下:

1.创建 DB2 的数据库访问类,它应该实现 IDAL 接口。

2.将 DB2 访问类编译成一个程序集。

3.测试和部署新的数据程序集到一台运行中的服务器上。

4.更改配置文件,指向新的数据库访问类。

无需更改或重新编译业务逻辑组件。

图 10. .NET Pet Shop 中 DAL 工厂类的实现

存储过程

通常我们都建议客户使用存储过程来访问数据库中的表。 原因如下:

  • 存储过程提供了封装查询的一种简洁机制。

  • 修改查询可以在不改变数据访问代码的情况下进行。

  • DBA 可以很容易地看到正在执行什么 SQL 语句。

  • 存储过程一般更安全,对数据库访问的控制也更容易。

  • 使用存储过程,可通过在存储过程中发送多个请求,避免与客户端的多次往返行程。

  • 存储过程与中间层生成的 SQL 相比,通常能提供最佳性能。

  • 存储过程提供了极好的封装 XML 查询和 XML 输入参数的方式。

存储过程的缺点在于,它们往往是专有的,不能跨平台移植。

然 而,要想最大程度地利用在数据库软件和硬件上已经花费的投资,开发人员往往对应用程序中使用的 SQL 针对具体数据库引擎进行优化,无论 SQL 是在存储过程中还是在中间层生成的。 这一点有一个很好的例子,就是唯一编号或者标识编号的生成,因为所有数据库执行此操作时都支持自己的特殊机制,所以用来生成唯一编号的 SQL 就往往是特定于所用数据库的。 一般总是有替代方案的,但是它们的执行速度都比不上专有解决方案。

对于 .NET Pet Shop,我们有意识地没有在应用程序使用存储过程,因为这在 Middleware 基准测试中会被看作是 .NET 解决方案一种不太公平的优势。 实际上,这方面的性能差异很小,因为应用程序相对比较简单,大多数 SQL 语句的执行计划都缓存在数据库中了。 但是, Middleware 基准测试规范不允许使用存储过程,哪怕只是包装简单的 SQL 语句,因此 .NET Pet Shop 3.0 没有使用存储过程。

缓存

最有效的提高数据库驱动的应用程序性能的方式,是避免对每次请求都访问数据库。 ASP.NET 提供了各种缓存机制以提高大多数应用程序中的性能。 ASP.NET 中使用缓存的两种主要方式是输出缓存和数据缓存。

.NET 缓存选项

页 面级输出缓存接收来自 ASP.NET Web 页的响应,并将整个页面存入缓存中。 页面缓存被设计成工作在 Web 层和中间层之间,缓存中间层方法的结果/数据,或在两层应用程序中缓存数据库调用结果。 第一版的 .NET Pet Shop 同时提供了一个页面级输出缓存版本和一个非缓存版本。 第三版只支持数据缓存,但是可以很容易地改为支持输出缓存。 对于 Windows Server 2003 和 IIS 6.0,有些输出缓存的页面(那些 VaryByParm="none" 而且有 Cache 'Anywhere' 指令的)还能在内核级进行缓存,Internet 客户端访问就更快了。 无论如何,任何输出缓存的页面(内核或者非内核缓存)Windows 应用程序服务器都可以在资源 (CPU) 消耗少得多的情况下,极快速地进行服务,因为实际上重新创建页面无需进行处理。

ASP.NET 输出缓存

最 早的 .NET Pet Shop 应用程序,版本 1.5,还使用了一种页面级输出缓存的变种,也就是部分页面缓存或称片段缓存来缓存页面的不同区域。 例如,缓存每个页面顶部的头信息。 然而,头信息取决于正在登录的用户(因此两个不同版本的页面都要缓存)。 ASP.NET 很容易允许这种操作,使用‘OutputCache’指令中的 VaryByCustom 属性即可。 使用 VaryByCustom 需要重写 GetVaryByCustomString 方法以获取头信息的自定义缓存。

ASP.NET 数据和对象缓存

对 象缓存(缓存 API)允许使用 .NET 框架在内部缓存引擎中存储方法调用或者数据库查询的结果。 由于已经深入了应用程序工作管道,数据缓存可能无法像输出缓存那样提供同样的性能提升,因为对每个请求仍然必须动态构造 HTML 页面。 但是,通过在中间层存储非易失数据,已经在完全动态的页面和减少数据库负载之间取得了很好的折衷。 例如,要在两个 Web 页中以不同方式显示同样的数据,或者在同一个应用程序不同页面中以不同方式使用已经缓存的对象或数据。

ASP.NET 缓存监视

监 视 ASP.NET 缓存系统中发生了什么,有几种方式。 首要的方法是使用 Perfmon,但是还可以使用 SQL Server 跟踪检查访问数据库的时间,这根据具体情况而定。 为了在 Perfmon 中监视缓存,ASP.NET Application 性能对象下选择 Output Cache Entries 和 Cache API Entries 计数器,将它们添加到 Perform 图。 还可以在 Perfmon 中监视周转率和点击率,检查缓存中是否使用了某个项目。

表 5. .NET 缓存选项摘要

缓存类型

优点

限制

输出缓存

提供了最佳性能

整个页面输出都缓存

片段缓存

(缓存用户控件)

实现很简单。 整个页面输出都缓存

有时间失效限制

缓存 API

页面中不同用户控件可以有不同的缓存超时

缓存控件可以跨页面共享。 需要分别缓存每个用户控件

Pet Shop Middleware 基准测试缓存规则

Middleware 公司为基准测试应用程序定义了严格规则:什么能够缓存,怎样缓存。 大体而言,页面级输出缓存是禁止的,但是应用程序中的一些地方允许中间层数据缓存。 以下数据允许缓存,不需要每次请求都从数据库刷新: 类别信息,产品信息,项目信息(库存数据除外)和某些帐户信息。 对于库存数据,无论何时项目添加到购物车或者用户定位到‘ItemDetails’页面时,库存中的当前量应该反映最新值。 对于帐户信息,用户名和密码对于每一个登录企图都要进行验证,用作计帐信息的地址也应该始终从数据库刷新,以确保它在结帐处理中是最新的。 这里也就意味着,可以使用设置了给定期限的数据/对象缓存将大多数产品搜索和浏览操作的结果缓存在中间层中。

基准测试的第二条规则是不应该允许页面级输出缓存;应始终要求 Web 服务器重新为页面创建要呈现的 HTML。 这是为了测试应用程序服务器生成动态页面的能力,而不是测试服务器从缓存拖出 HTML 有多快。

Pet Shop 3.0 缓存实现

对 于这一版本的应用程序,我们使用 ASPX 页面后代码中的数据缓存,来缓存中间层(业务逻辑层)请求的结果。 以下示例代码说明了如何访问 ASP.NET 缓存 API 从缓存检索信息。 该示例基于 Pet Shop 应用程序中的类别查询代码,category.aspx.cs。 在 Pet Shop 中,用户可以在五个预定义宠物类别中选择一个,查看该类别中的动物列表。 代码所做的第一件事是检查数据是否已经缓存,这是通过用类别 id 作为键查找数据缓存中的一个元素来实现的。 如果这个元素不存在,要么是因为数据还没有缓存,要么是当前缓存已经过期,将返回 null。 如果元素存在,就从缓存中拖出数据,并转换为合适的类型。 如果数据不在缓存中,调用中间层查询数据。 中间层查询的结果然后添加到缓存中,期限为从现在开始 12 小时。 或者,可以根据固定时间、对另一缓存项目的依赖,或者通过提供一个可以用来清除缓存的回调函数使缓存过期。

			// Get the category from the query string
string categoryKey =
WebComponents.CleanString.InputText(Request["categoryId"],50);

// Check to see if the contents are in the Data Cache
if(Cache[categoryKey] != null){

// If the data is already cached, then used the cached copy
products.DataSource = (IList)Cache[categoryKey];

}else{

// If the data is not cached,
// then create a new products object and request the data
Product product = new Product();
IList productsByCategory = product.GetProductsByCategory(categoryKey);

// Store the results of the call in the Cache
// and set the time out to 12 hours
Cache.Add(categoryKey, productsByCategory, null, DateTime.Now.AddHours(12), Cache.NoSlidingExpiration , CacheItemPriority.High, null);

products.DataSource = productsByCategory;
}

// Bind the data to the control
products.DataBind();

小结

.NET Pet Shop 的体系结构已经进行了改进,能够在部署选择方面提供更灵活的解决方案,应用程序能够更加容易地进行自定义,适应业务模型中的变化。 尽管有所有这些变化,Pet Shop 的性能与 2.0 版实现大致相同,说明了 Microsoft .NET 框架在 J2EE 之外提供了另一种可行的企业级解决方案。 通过 .NET Pet Shop 和 J2EE Pet Store,架构师和开发人员可以使用功能完全一样、说明了各自平台上最佳编程实践的参考应用程序,一对一地比较 .NET 和 J2EE。 即将进行的 Middleware 基准测试将测试新的 .NET Pet Shop 3.0 实现,将比较它与两个新 J2EE 实现——一个基于 CMP 2.0,另一个基于纯粹的 JSP/Servlet 体系结构(不使用 EJB)的性能。 测试将由 Middleware 公司进行,在运行着各种 J2EE 应用程序服务器的服务器端发布。 将组成一个 J2EE 专家评委会监督这一基准测试,以确保对被测试产品的公平性以及所有实现都符合规范和最佳准则。 此外,已经邀请了主要的 J2EE 应用程序服务器供应商,加上 Microsoft 来参与这一基准测试,他们将对规范进行评价,提供供测试的实现,并现场进行微调和优化,参与测试过程。 Microsoft 选择全面参与第二轮测试。 可以到这里 了解 Middleware Application Server 测试第一轮的细节,测试基于两个基准测试应用程序:早期的 .NET Pet Shop 2.0 和一个基于 BMP 的 J2EE 实现,或者下载完整的报告

附录 A: 从版本 2 到版本 3 的更改

项目

说明

原因

1

创建数据库访问层 (DAL)。

可以将业务逻辑从数据库访问代码中完全分离出来,因此可以无需更改业务逻辑代码,即可更换数据库供应商。

2

为所有瘦数据类(模型)创建公共的项目。

模型项目只包含保存数据的瘦类,可以用在应用程序的每一层,作为传输数据的容器。所有模型类都通过 [Serializable] 标记支持序列化,以添加对群集和任何未来物理部署中变化的增强支持。

3

在 Components 项目中删除对 System.Web 的引用。

这是一种好的设计实践,因为可以使中间层组件用于不同类型的 UI。

4

将一些自定义服务器控件改为 Web 用户控件;然而 Pager 控件仍然保留为自定义服务器控件。

标头和标题控件含有许多 HTML/UI 内容,因此如果实现为 Web 用户控件更易维护。 Pager 控件处理的是查询字符串的操作,视图状态中数据的使用,因此作为自定义服务器控件更合适。

5

为 Oracle 创建了 DAL 实现。

为了支持 Oracle 数据库,创建了特定的 Oracle DAL,可以使用 Oracle 特定的驱动程序

6

DAL 层现在实现了工厂模式 [GoF] 以加载相应的供应商特定的 DAL。

为了隐藏后端所使用的数据库,使用工厂方法将接口返回到要用到的 DAL 层。

7

模型类中的所有公共字段都转换为属性。

这样字段的存储机制就可以隐藏起来,如果要看什么函数修改了某些数据,这提供了一个很好的在代码中添加断点的地方。

8

创建数据库访问层 (DAL)。

可以将业务逻辑从数据库访问代码中完全分离出来,因此可以无需更改业务逻辑代码,即可更换数据库供应商。

9

将所有静态方法改为实例方法。

根据评论反馈进行的修改

10

将 assemblyinfo.cs 中的版本号改为与部署匹配的具体版本。

在 DALFactory 对象中加载程序集时,允许指定证据。

11

在 Visual Studio .NET 解决方案中添加构建前和构建后的步骤。

这样,在项目编译后,就可以对具体程序集运行 gacutil 和 regsvcs 实用工具。

12

将订购业务组件改名,根据其执行的功能而非实现机制。

对其他开发人员而言理解组件的功能更直观。

13

创建配置工具辅助应用程序的设置。

需要以管理员组成员的身份创建应用程序事件日志源。 确保完成最简单的方式是提供一个简单的工具,可以在部署后运行。

14

将代码修改为允许帐号和产品数据库以及定单数据库使用不同的 DAL。

对用户请求的响应应该能够使用混合数据库部署模型。

15

页面中添加页面输出缓存;但是基准测试时要删除。

有用户请求说明如何重写 VaryByCustom 函数使标题和标头控件等页面能够在 default.aspx 这样的页面中缓存。

16

将处理流程控件类添加到 Web 应用程序中。

根据评论反馈做的修改,为帐号或购物车这样的 Web 区域提供单一位置来控制定位和状态管理。

 
一、Model主要功能: 1、 将每一个“业务实体”抽象成“(瘦数据)类”,可以很好地“划分”各个“对象”,操作更加清晰 2、 用于在应用程序各层之间传递数据,被用做传输数据的“容器” 3、 这就是所谓的“建模”过程! 4、 Model各个类(Model文件夹中的各个文件)划分或者说编制的原则,更趋向于模拟整个系统中的业务实体 二、实现细节: 1、 PetShop中Model的规划数据库表的关系: (1) AccountInfo类——Account表 (2) AddressInfo类——无直接对应关系(对应Account表中一部分字段) (3) CartItemInfo类——无直接对应关系 (4) CreditCardInfo类——无直接对应关系 (5) ItemInfo类——Item表 (6) LineItemInfo类——无直接对应关系 (7) OrderInfo类——Orders表 (8) ProductInfo类——Product表 2、 为每一个Model中的类都标记了[Serializable],说明这些类可以被传行化,但是不能被继承! 3、 AccountInfo.cs文件:用户在网站注册的信息,及喜好选择情况 4、 使用构造函数可以初始化私有字段;使用属性可以读取私有字段(但使用属性不能设置私有字段的值) 5、 其中包含一个AddressInfo类的私有变量,和一个AddressInfo类的属性 6、 命名空间为PetShop.Model 7、 AddressInfo.cs文件:用户真实的个人姓名、住址和电话号码等信息 8、 AccountInfo不同的是,AddressInfo类允许使用属性设置私有变量的值 9、 CartItemInfo.cs文件:描述购物车中每一种所选商品的信息的类 10、 该“类”对象的某些信息(如这里的Subtotal属性)可能并不是此类的“自然信息”,而需要经过简单计算而得到!这些简单但必要的信息也要在类的设计中体现出来! 11、 CreditCardInfo.cs文件:表示特定一张信用卡的信息 12、 ItemInfo.cs文件:一个Item指的是category"product"item,如猫"波斯猫"成年男波斯猫(或成年女波斯猫)。这个文件表示一个Item的所有信息 13、 productDesc字段的作用? 14、 LineItemInfo.cs文件:注意CartItemInfo类的区别!LineItemInfo是用来描述用户最终确认的订单当中的某一种类的产品的信息的类 15、 同样包括了Subtotal属性 16、 OrderInfo.cs文件:用于显示用户某一个订单具体信息的类,在此一个订单当中,可能包括多个商品种类,即包括多个LineItemInfo对象(实际上在OrderInfo类中也确实存在LineItemInfo类型对象的一个数组!) 17、 ProductInfo.cs文件:包括一个特定Product的信息,如波斯猫 三、启发: 1、 来自Directory项目结束后的启发,以后做设计的时候,要将每个实体抽象为一个类,在整个系统中进行操作。 2、 在任意一个类当中,可能不只包括此实体类的自然信息,也可以包括一些对其他地方数据调用有用的属性信息,如根据数量和单价计算出来的总价属性,或者标志此实体的直属上级实体的属性 四、问题: 1、 忽然发现在MSDN上有文章,关于数据实体的:浏览 2、 抽象这些业务实体模型为瘦数据类的原则是什么?什么样的业务实体可以被抽象,或者说进行抽象后更有意义? 3、 ItemInfo类中,productDesc字段的作用? 一、IDAL主要功能: 1、 这完全是“工厂模式”的一部分实现而已 2、 这是一组接口类,其中包括了每个要公开的数据访问方法。为每个数据库产品单独编写的DAL(数据访问层)都要实现这组接口所定义的方法 3、 也就是规定了在DAL中编写的“对用户账号进行操作的类”所必须执行的方法! 4、 IDAL要达到的目的是:实现业务逻辑(BLL)数据库访问(DAL)的完全分离!!! 5、 IDAL各个类(IDAL文件夹中的各个文件)划分或者说编制的原则,更趋向于“将对数据库的不同操作进行归类”,考虑的主要方面是数据库操作!!!例如,有对用户账号进行的一系列数据库操作,则将这一系列操作统一放置于IAccount接口(将来实现后的Account类)文件当中 二、实现细节: 1、 IAccount.cs文件:为针对不同数据库产品编写的“操作用户账号的类”所必须实现的一系列方法定义契约 2、 IInventory.cs文件:定义“操作库存量的类”所必须实现的一系列方法;或者说将操作库存量的一系列(所有)方法做一个汇总 3、 IItem.cs文件:定义“操作某一Item的类”所必须实现的一系列方法。(Item在Model中定义了,是指具体某一类别的Product,如男猫或女猫) 4、 对于其中的GetItemsByProduct()方法,返回的是一个ArrayList的接口类型(IList)的对象(见问题部分!) 5、 IOrder.cs文件:定义了一组DAL层中“操作用户订单的类”必须执行的方法。其中包括“添加一张新订单”的方法Insert()和根据一个已有的订单号取得此订单详细信息的方法GetOrder(),此方法返回的是一个OrderInfo对象。(Model中的OrderInfo类模型定义了用户的某一张Order中相关的信息,如发货地点,总价,信用卡号码等等) 6、 IProduct.cs文件:定义类一组在DAL层中编写的“对Product进行操作的类” 7、 IProfile.cs文件:定义一组在DAL层编写的“对用户Profile进行操作的类” 三、启发: 1、 这样就可以让在BLL层只针对IDAL层定义的接口进行编程(使用IDAL接口定义的这些方法)就可以了!!!无论在底层使用了什么厂家的数据库产品,有区别的只是针对此数据库产品编写的DAL层(相同的方法,如SignIn()方法,对于不同的数据库产品,可能有不同的实现方式!),而不会影响到上层的BLL层已经编写好的内容! 2、 从这里可以看到软件架构师和程序员工作上的区别!架构师要负责的是搭建系统的层次结构,定义接口;而程序员要负责的是针对接口的具体代码实现过程! 3、 这个IDAL接口的使用,主要是为了保证在底层数据库实现,甚至数据库产品发生变化的时候,不需要对上层BLL层的业务逻辑进行大量的修改!BLL层针对IDAL接口编程即可!!! 4、 IDAL文件夹中定义的所有的接口中的所有的方法,包括了整个程序要对数据库进行操作的所有方法 5、 由于PetShop只是一个演示程序,所以若对数据库操作的某一类别(如对Account进行操作)中定义的“操作类”不够用(如除了接口中定义的几个方法外还需要其他Account操作),还可以在接口中追加其他的方法,用以约束DAL层的实现类(如Account类)必须执行这些新增加的方法! 四、问题: 1、 定义这组接口后,如何保证为每个单独的数据库产品编写的DAL都执行这组接口所定义的方法?(答案:编写DAL的时候必须刻意保证,否则就失去了定义IDAL层分割BLL和DAL层的意义!!!) 2、 既然在实现GetItemsByProduct()方法的时候,也是要把返回的所有Item对象添加到一个ArrayList当中去,但为什么GetItemsByProduct()方法返回的不是一个ArrayList对象,而是一个IList接口的对象呢?仅仅是基类引用的方法吗?这里的基类引用有什么用呢?是否是由于为了不限制使用的数组形式?执行IList则可以使用ArrayList,也可以使用其他形式的数组??? 3、 IProduct.cs文件中为何要将查询条件参数定义为一个string类型的数组?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值