图 1:三层图现在我们有一个简单的逻辑模型。它是如何起作用的?它有助于我们考虑各个逻辑组之间的边界。每个逻辑层应尽量与其他层独立。理想的情况是,图层中的更改应该对整体产生最小的影响。例如,如果将数据存储从 SQL Server 更改到 XML 数据文件,唯一受到影响的图层应是中间层图层。用户界面应该根本无需考虑更改。这会使您进行思考:如何实现解决方案的实际编码以实现此原则。另外,逻辑层有助于我们考虑安全问题。各个图层之间的边界都存在潜在的安全漏洞。而且,各个图层可能有自己特定的安全措施(SQL Server 权限、.NET 运行时权限、ASP.NET 安全等)。同样,我们稍后会在本节中详细讨论这个问题。物理体系结构确定逻辑层后,考虑物理层也很重要。例如,您可以在同时安装有 SQL Server、Internet Information Server、ASP.NET 和 .NET 运行时的单个实际计算机上实现这个应用程序。这将是一个物理层。但更可靠且可扩展的方法是:在由三个 Web 服务器组成的簇上部署 Web 窗体,在两个应用服务器上部署 .NET 组件程序集,在两个故障恢复模式的 SQL Server 上部署数据库。这样产生的物理体系结构将七个 Windows 服务器包含在三个主要组中:Web 簇、组件簇和数据库簇。如果您了解系统的不同逻辑部件可以位于不同的计算机上,您可能会实现不同的代码。对于我们的示例,我们采用一个有效且强大的两层模型:Web 服务器托管用户界面和组件,数据库服务器托管 SQL Server 数据存储。如果通信量非常大,这个模型使我们可以灵活地在簇中添加更多的服务器,并使其保持足够的简洁以便于处理。下面的图像显示了此物理体系结构与前面定义的逻辑体系结构之间的映射关系。 图 2:物理体系结构与三层体系结构之间的映射关系正如您看到的那样,逻辑体系结构和物理体系结构不必相同。在规划阶段还要考虑一项内容:安全。安全规划 Microsoft 有一个关于安全性与软件这一主题的歌诀:“Secure by design, secure by default, and secure by deployment(设计安全,默认安全和部署安全)”。即,在安全中设计,期待系统在默认情况下是安全的,以及创建可以在安全环境中成功部署的解决方案。安全始终是重要的。既然越来越多的软件要在公用的 Internet 上“生存”,编写安全的软件就更加关键。对于我们而言,幸运的是,.NET 运行时和 Windows 操作系统提供广泛的安全选项和功能,我们可以轻松地将其包含在我们的应用程序中。无需过分注重标识和消除联机解决方案中安全漏洞的细节,我们可以指出其中一些最常见的漏洞并指出我们的应用程序规划如何进行处理。注意:有关可用选项的详细信息,请参阅 Microsoft Security Developer Center。缓冲区溢出这可能是已编译应用程序中最常见的安全漏洞。由于我们将使用 .NET 运行时,而它是设计用来在内存中安全运行的,因此不太可能发生缓冲区溢出。此外,我们使用 Microsoft Visual Basic® .NET 对解决方案进行编码,而 Microsoft Visual Basic® .NET 不像 C 或 C++ 那样容易受到缓冲区溢出问题的影响。但是,即使我们打算用 C++ 创建组件,我们还可以使用编译程序的特殊功能,GS 转换,来保护我们免受大多数缓冲区溢出的攻击。数据库攻击另一种常见的安全漏洞可能会使恶意用户获得访问存储在数据库中的原始数据的权限。为了防止黑客获得数据的控制权,我们仅使用 SQL Server 存储过程,而不使用“内联查询”。这样可以大大减少试图在输入流中插入其他 SQL 命令的攻击。我们还在程序中多个位置处使用输入验证,以确保所有输入仅包含有效的字符。交叉站点脚本攻击对 Web 应用程序进行的常见攻击还有一种,它涉及到用户在输入流中添加客户方脚本,这类攻击将执行附加的对话并诱骗用户将个人数据发送到黑客自己的 Web 站点。要解决这个问题,我们使用 ASP.NET 1.1 的一个新功能,过滤出这种恶意代码的所有输入,防止将它置入系统中。显示屏幕上还包含附加代码,它将自动禁用任何脚本或显示可能会插入到数据存储中的标记。至此,我们已获得了应用程序的逻辑模型和物理模型,以及确保实现方案包含的安全功能清单。拥有了这些以及目标声明和用户方案,我们可以开始这次“编码前”探险的最后一部分了。完成设计文档 在直接进入项目的编码部分之前,需要花一点时间实际勾画出应用程序的逻辑组件,这非常重要。在我们的示例解决方案中,我们要实现解决方案的三个逻辑组件:数据库、.NET 数据访问组件和 ASP.NET 用户界面。在下面几篇文章中,我们将非常详细地介绍如何实现这些组件。但现在,我们只是勾画出每个组件的大致轮廓,讨论过程中最重要的方面,即文档化组件间的交互。数据库对于 DotNetKB 应用程序,我们需要将数据存储在三张表中:主题、问题和回答(请参阅下图)。 图 3:主题、问题和回答表我们需要使用存储过程,以使中间层组件也可以安全地访问数据。有关数据库的细节,我们将在下一篇文章中讨论。这里,我们只是指出:列出表名称及所有列细节、默认索引和存储过程列表的数据库文档,应该包含在一个完整的数据库设计文档中。即,文档中应该具有成功实现系统数据存储部分所需的详细信息。注意:如果留心的话,您可能会注意到我们未提及将专家数据存储在数据库中。只是为了使项目更加有趣(同时给我们一个机会使用直接 XML 数据存储),我们将专家信息存储在一个 XML 数据文件中。数据访问组件数据访问组件设计文档描绘与数据存储系统的交互以及与用户界面的交互的所有细节。在有些系统中,数据访问组件实际上是处理过程中各种问题的多个程序集。例如,可能会有一系列业务规则呈现在与数据存储和检索完全独立的用户界面上。在这种情况下,将业务组件与数据访问组件分开实现可能比较明智。在我们的示例中,实际实现的是两个单独的组件:Message 组件和 DataAccess 组件。如果在支持基于 XML 的数据的传输服务(例如 SOAP Web Service)中进行规划,这种面向消息的实现方案将会特别有成效。消息组件消息组件定义一系列用于在各图层之间传输数据的类。这些消息可以作为二进制或 XML 文本数据存在。消息图层的价值在于:保护系统的其余部分,使其独立于数据存储实现方案的具体细节,例如 SQL Server、XML 文件等。此外,通过实现消息图层而不是更复杂的“智能对象”库,我们的解决方案可以更轻松地支持那些不能同时发送数据和类级别逻辑的远程调用服务,例如 XML-SOAP。下面是一个消息类示例,在该示例中实现了 Topic 消息及其集合:Public Class Topic Private _ID As Integer Private _Title As String Private _Description As String Public Property ID() As Integer Get Return _ID End Get Set(ByVal Value As Integer) _ID = Value End Set End Property Public Property Title() As String Get Return _Title End Get Set(ByVal Value As String) _Title = Value End Set End Property Public Property Description() As String Get Return _Description End Get Set(ByVal Value As String) _Description = Value End Set End PropertyEnd ClassPublic Class Topics Inherits System.Collections.CollectionBase Default Public Property Item(ByVal index As Integer) As Topic Get Return CType(List(index), Topic) End Get Set(ByVal Value As Topic) List(index) = Value End Set End Property Public Function Add(ByVal s As Topic) As Integer Return List.Add(s) End Function Public Sub Remove(ByVal index As Integer) List.Remove(index) End SubEnd Class注意:如果您已尝试过面向消息的设计,便会了解我们想要使这些消息类系列化,以便在应用程序图层之间轻松地来回发送。幸运的是,.NET 运行时知道如何进行这项操作,而无需我们做过多的工作。但是,当我们学习创建消息的文章时,我们将详细讨论 .NET 运行时如何系列化类,以及我们如何进行操作以使代码中的过程最优化。在后面实现消息组件和数据访问组件时,文章中将介绍此方法的细节。设计文档将包含一个由所有信息及其属性与数据类型组成的列表。现在,我们只是考虑如何使用此消息方法来封装图层间的数据传输,如何创建一种与本地方案和远程方案配合使用的常规数据服务。数据访问组件定义消息类的概念后,数据访问组件可以集中精力处理与数据存储系统直接对话的细节,并以正确的消息格式返回信息。在我们的示例中,这将涉及到使用来自用户界面的请求映射 SQL Server 存储过程,并创建可返回到用户界面进行显示的消息(或消息集合)。例如,下面是一个数据访问组件的一部分示例代码,该组件将从数据存储中检索单个 Topic 记录,并将正确的消息格式返回到用户界面。Public Function GetTopicRecord(ByVal ID As Integer) As Messages.Topic Dim t As Messages.Topic = New Messages.Topic cn = New SqlConnection(secureConnectionString) cd = New SqlCommand("GetTopic", cn) cd.CommandType = CommandType.StoredProcedure cd.Parameters.Add("@ID", ID) cn.Open() dr = cd.ExecuteReader() dr.Read() With t .ID = ID .Title = dr("Title") .Description = dr("Description") End With Return tEnd Function设计文档将包括一系列用于处理来自用户界面的各个请求的类和方法,并含有有关调用哪个存储过程以及返回何种消息格式的详细信息。同样,我们将在后面主要介绍数据访问图层的文章中讨论此过程的细节。Web 用户界面最后,用户界面设计文档将包括完成各种方案所需的所有用户输入和显示。通常来说,用户界面文档包括界面机制的细节以及使用户界面呈现唯一性的图形设计元素。例如,配色方案、字体和总体页面设计,与用于获取搜索查询的正确数据的输入名称和输入数量一样重要。要使文档简洁,通常在一个与图形设计单独的文档中概要描述机制细节。这是我们将要在示例中做的工作。在后面的一篇文章中,我们将创建一个综合性用户界面文档和实现方案,详细说明每个屏幕的元素和相关操作。在另一篇文章中,我们将处理应用程序有关图形的各个方面,重点讨论作为一种外观服务的级联样式表的使用。下面是一个典型的用户界面描述,它涉及“主题”编辑方案。主题输入屏幕“主题”屏幕将显示所有当前主题(主题 ID 和主题名称)的一个缩略列表,在每个主题旁边还将显示一个“编辑”链接。单击“编辑”链接将会调用关联的主题记录并将其显示在一系列的输入框中。“标题”和“描述”是可编辑的,而“主题 ID”是只读的。用户可以编辑标题和描述,然后按“保存”按钮将更改写入数据存储。输入将被验证。两者都是必需的输入项,“标题”的长度限制为 30 个字符,“描述”的长度限制为 500 个字符。更新完成后,将显示一条响应消息指出已确认更新;如果更新失败,则显示一条消息指出错误状况。用户还可以删除现有的主题记录,方法是单击列表中的“编辑”链接,审核显示屏幕上的记录细节后,单击“删除”链接。删除完成后,将显示一条响应消息指出已确认更新;如果更新失败,则显示一条消息指出错误状况。请注意,用户不能删除与现有问题或回答相关联的主题。此外,用户可以完整地添加新主题记录,方法是在初始显示屏幕上单击“新建主题”链接。将显示“标题”和“描述”输入(不显示 ID 输入)并提供一个“保存”按钮。输入将被验证。两者都是必需的输入项,“标题”的长度限制为 30 个字符,“描述”的长度限制为 500 个字符。更新完成后,将显示一条响应消息指出已确认更新;如果更新失败,则显示一条消息指出错误状况。利用上面的叙述,您可以轻松地实现一个完整的功能屏幕。判断一个好的设计文档的方法是:它能够使读者完成工作,且不会提出额外的问题。最终的用户界面设计文档将包括应用程序中每个屏幕的此类叙述。小结并付诸行动 我们简要介绍了数据库、中间层和用户界面实现方案的最终设计文档。加上体系结构和初始规划文档,它们形成了我们的完整设计包。在实际的情况中,即使是最小的系统,完成这些文档也至少需要几个小时。对于大型系统,可能需要几周甚至可能几个月的时间。有些人可能会对此有一点挫败感,但是通过事先完成这些工作,您可以在进入项目的编码阶段之前很早就了解完成解决方案面临的几乎所有主要障碍。这样可以减少编写实际代码的时间,并且还可以减少您会遇到的错误和障碍的数量。在下一篇文章中,我们将讨论使用 Visual Studio .NET 在 SQL Server 中建立数据存储系统的有关细节。我们将定义数据表,创建必需的存储过程,并设置正确的数据访问,以确保任何组件和数据本身之间具有安全可靠的连接。至此,您已经看到了一个如何创建应用程序规划的可用示例,可以开始考虑如何在您自己的工作中使用这些元素来提高项目的整体质量和生产率。有关项目规划以及规划如何影响软件质量的详细信息,请参阅 Steve McConnell 的 Software Project Survival Guide。Mike Amundsen 提供培训、演讲和咨询服务。要了解他的详细信息或与他联络,请访问他的站点 http://amundsen.com/。此外,还可以在 http://www.amundsen.com/DotNetKB 站点上找到本文的更新和相关资料。 |
温馨提示:喜欢本站的话,请收藏一下本站!