目录
在 ASP.NET 中实现 AJAX 的方法
实现 ASP.NET AJAX 的直接方法
UpdatePanel 和侦听器模式
控制频带外调用
页面方法与 Web 服务方法
我实现 ASP.NET AJAX 的方法
除非您在过去的 12 个月里没有上过网 - 也许是到远方的热带小岛度假去了或参加了真人秀比赛 – 否则您应该对 AJAX 有所耳闻。但是,保险起见,我还是简要介绍一下。
首先,缩写词 AJAX 代表 Asynchronous JavaScript and XML(异步 JavaScript 和 XML)。接着是它的用途:它是一项真正的突破,有了 AJAX,那些以往看来无法实现或不切实际的解决方案都将成为可能。最后是 AJAX 的组成。本质上,这不是一项技术,而是一个概括性术语,表示利用已面市若干年的客户端 Web 技术(例如 JavaScript、级联样式表 (CSS)、DHTML 和 XMLHttpRequest)的强大组合来构建大量浏览器应用程序。
目前可用的大部分浏览器均支持功能的普通集 - Web 开发人员可使用这些功能来构建交互性强、刷新快速且能在客户端上执行大量工作的应用程序。利用这些功能,AJAX 应用程序能够为用户带来与使用桌面应用程序相似的极佳体验。此外,AJAX 也使创建“混合”应用程序比以前更容易。混合应用程序是一种 Web 应用程序,它将来自多个来源的信息结合在一起(例如,将 Microsoft? Virtual Earth? 与房地产销售信息结合起来,以创建有用的房地产工具)。
但是,我觉得,正因为 AJAX 的丰富性和重要程度,它反而会被人们很快遗忘。不可思议?之所以这样认为,原因是我觉得 AJAX 会被这个行业中的每个人所消化吸收,从而变成无需思索便会执行的日常生活中的基本组成部分 - 就像现在我们觉得没必要强调 XML 或 HTTP 的使用一样。
Microsoft ASP.NET AJAX(以前称为“Atlas”)在 2005 年 9 月的 Microsoft Professional 开发人员会议上公诸于众,它为 ASP.NET 2.0 增添了许多新能力(请参阅 ajax.asp.net),所有这些能力都是为了简化向网站添加基于 AJAX 的功能的方法。在本月的专栏中,我将详细介绍 ASP.NET AJAX,深入探讨它的一些关键功能。阅读本专栏之前,您应具备相关基本概念和工具的知识。有关详细介绍,请参阅 MSDN? 杂志 2006 年 7 月号上的文章“Atlas 出炉:ASP.NET Atlas 为您期待已久的 AJAX 样式的网站提供支持”,作者 Matt Gibbs。此外,还可参阅提要栏中的“目前仍同步”以了解其他相关信息。
在 ASP.NET 中实现 AJAX 的方法
使用 AJAX 可构建哪些新的应用程序功能?或者,明确点说,使用异步 JavaScript 调用和浏览器的对象模型可构建什么功能?支持 AJAX 功能的主要技术有三种:远程方法调用、客户端数据绑定和视觉效果。远程方法调用听起来有点太含糊,所以本文中仅对其中的部分页面回发和频带外请求进行探 讨。
如何将新的或现有的 ASP.NET 应用程序转换为 AJAX 应用程序?据统计,目前可用于 AJAX 开发的框架超过 100 个 - 它们支持多种平台并采用不同的编程方法。大体上,我趋向根据这些 AJAX 框架的功能将它们分为三个主要类别:回调框架、UI 框架和完整框架。
回调框架由客户端和服务器库的简单集合组成。它只允许您从客户端调用服务器端代码片段,以序列化格式移动输入和输出参数。典型的 UI 框架是从现有的专业控件库演变而来,它提供高级网格控件、图表控件和树控件。这些控件支持异步回发和在客户端上注入用于自动刷新页面的 JavaScript 代码。完整框架则提供包含控件和应用程序服务在内的丰富编程模型,更适宜同时用在客户端和服务器上。Microsoft ASP.NET AJAX 属于第三种类别。
如果您使用的是商业控件套件,那么升级到新一代支持 AJAX 的版本后您不会有任何的不适应感觉。如果您完全在内部开发应用程序,并要保护表示层和后端层,那么完整框架是最可行的选择。而简单框架则只用于将快速回调 功能添加到现有 ASP.NET 应用程序(版本 1.1 和 2.0)中。
ASP.NET 2.0 提供内置脚本回调 API,这一点我已在本专栏中多次提到,例如“最先进的技术:ASP.NET 中的脚本回调”和“Cutting Edge:Custom Script Callbacks in ASP.NET”(英文)。在本专栏附带的代码中,包括一个用于远程方法调用的非常简单的 AJAX 框架演示。它仅包含 50 行代码,一部分用 JavaScript 编写,一部分用托管代码编写。当然,它无法与 ASP.NET AJAX 相比,但它可用作将基本 AJAX 功能添加到 ASP.NET 1.1 应用程序的核心代码。
实现 ASP.NET AJAX 的直接方法
ASP.NET AJAX 包含两种截然不同(但不互相排斥)的 API:客户端和服务器。您可以通过直接客户端编程、传统服务器端编程或这两者的任意组合构建 AJAX 功能。本质上,任何基于 AJAX 的页面都需要一些客户端 JavaScript 代码来处理浏览器的文档对象模型 (DOM) 和任何特定于应用程序的扩展。但不必将这类脚本代码编写工作留给 ASP.NET 程序员。事实上,框架可生成专门设计的脚本代码作为服务器端控件的输出。这种形式的间接页面更新是目前为止将 AJAX 功能添加到新的和现有的 ASP.NET 2.0 页面的最简单方法。在 ASP.NET AJAX 中,页面更新可由服务器控件(UpdatePanel 控件)所自动插入的一段客户端代码来管理。
UpdatePanel 控件代表 ASP.NET AJAX 以服务器为中心的编程模型的神经中枢。它允许您执行服务器端代码并将已更新标记返回到客户端浏览器。您可能想知道这与传统的回发有什么不同。它们的区别在 于回发的实现方式 – 传统的回发是整页刷新,而 UpdatePanel 控件会设法发送一个频带外请求以取得刷新标记,并在响应就绪后更新 DOM 树。
ASP.NET 以客户端为中心的编程模型的重心是放置远程端点(通常为 ASP.NET Web 服务和 Windows? Communication Foundation 服务,但也可能是其他内容)调用的能力。直接从客户端浏览器启动时,对远程端点的调用需要 JavaScript 代理和 JavaScript 代码片段。客户端数据绑定可视为传统 JavaScript 运行时和 DOM 的扩展。在纯粹的客户端编程风格中,首先会连接到远程端点,然后下载数据,并将数据绑定到 DOM 子树。模板结构和一些状态信息保存在客户端上,只有原始数据从服务器移动到客户端上。
在 ASP.NET AJAX 中有三种主要的编程方法。图 1 概要介绍了这些工具以及它们的适用环境。
Figure1在 ASP.NET AJAX 中编程的方法
方法 描述 使用
UpdatePanel 包含一组服务器控件,监控这些控件的回发和呈现过程。通过脚本拦截和处理任何由所包含控件产生的回发请求。页面的更改会通过 DHTML 来应用。 如果您的团队不擅长 JavaScript,或者您希望将公开给客户端编程的信息降到最少,则使用此方法。如果您需要保护应用程序中任何敏感的业务逻辑,也建议使用 UpdatePanel。
远程方法调用 概括性术语,表示异步调用页面方法及本地和外部 Web 服务。调用通过 JSON 数据流以独立于类型的方式移动输入参数和接收返回值。要触发调用并将更改应用于客户端,需要强类型化 JavaScript 代码。 当您需要使用以异步方式触发和控制远程操作的智能客户端时,请使用此方法。此方法需要 JavaScript 编码来处理返回值和更新当前 DOM 中任何受结果影响的部分。
客户端数据绑定* 完全用 AJAX JavaScript 编写的两个客户端控件,用于实现基于模板的绑定。它们是用于多记录视图的 ListView 和用于单记录视图的 ItemView。这两个控件和客户端数据源以及筛选组件组合在一起。 当您需要 DHTML 应用程序的现代型跨浏览器版本时,可以使用此方法。绑定客户端数据后,最后得到的页面包括一厚层的 JavaScript 和/或 XML Script,并且没有任何托管代码(脚本管理器控件除外)。
UpdatePanel 和侦听器模式
UpdatePanel 控件所代表的编程风格是:无需整页刷新,也无需客户端编程,即可更新页面内容。在 ASP.NET AJAX 术语中,这称为部分呈现。在支持此功能的组件中,UpdatePanel 控件是最显眼的一个。但是,在部分呈现的内部实现的背后,真正的中枢是 ScriptManager 控件。不过,UpdatePanel 控件依然是开发人员编写部分更新的页面时使用的主要工具。
可通过以下两种方法之一更新网页 - 手动单击“提交”按钮或以编程方式调用 DOM 表单对象的提交方法。在这两种情况下,浏览器都会冻结当前页面并向后端 Web 服务器发送新请求。然后传入的响应会替换现有内容。
UpdatePanel 控件在此过程起关联作用。它截获表单提交,捕获正在发送的任何信息,然后根据 XMLHttpRequest 通过频带外调用发送同样的信息。UpdatePanel 控件还会加入一些其他信息,以指示要在服务器上处理和呈现哪些控件,从而实现部分页面呈现。
侦听器模式完整描述了由 UpdatePanel 控件所导致的行为。该模式引用观察对象调用并在调用者和接收者之间注入自己代码的任何外部组件。这样,外部控件将完全控制操作,控制如何完成任务,并将有 效响应返回到调用者。图 2 说明在 ASP.NET AJAX 中此模式的实现。
图 2UpdatePanel 控件和侦听器模式
注入客户端页面的脚本代码为表单的 onsubmit DOM 事件注册一个处理程序。这个新处理程序只是将传统请求替换为用于完成 XMLHttpRequest 并传递其他信息的请求。特别是,它将负责回发的 UpdatePanel 控件名称加到现有输入字段列表中。下面是具有可分页网格的页面的修改内容:
ScriptManager1=UpdatePanel1|GridView1&
__EVENTTARGET=GridView1&
__EVENTARGUMENT=Page%241&
__VIEWSTATE=...&
__VIEWSTATEENCRYPTED=&
__EVENTVALIDATION=...
ScriptManager 伪参数引用负责回发的 UpdatePanel 控件的 ID。只有与指定 UpdatePanel 控件关联的控件才会刷新,它们的已修改标记以及已更新的视图状态信息会发送回浏览器。
部分呈现是各种 AJAX 框架中的常用功能,尽管内部实现方法可能有所不同。大部分差异与用来关联可更新控件与请求的方法有关。在 ASP.NET AJAX 中,可更新控件在最外面的容器控件(UpdatePanel 控件)中进行了分组。该容器内的所有内容都会呈现出来以进行标记 - 这代表当前所显示页面的增量。另一个方法是要求各个控件以编程方式在框架上注册,以呈现 AJAX 式回发。这与在 ASP.NET 2.0 中使用支持控件状态的控件时发生的情况类似。
与分组容器中的控件相比,更精确、灵活的方法是让每个控件决定如何呈现 AJAX 式回发。但是,您还需要其他源代码指令或使用临时控件。虽然适用于控件库和其他此类产品,此方法却不太适用于诸如 ASP.NET 之类的 Web 框架。
UpdatePanel 控件是从 System.Web.UI.Panel 派生而来的类。作为子 ASP.NET 控件的无 UI 容器,UpdatePanel 可包含任何 ASP.NET 服务器控件,不需要使用任何支持 AJAX 的特殊控件。通过使用 UpdatePanel,可以使用与传统的 ASP.NET 相同的应用程序模型和编程风格在服务器上完成 AJAX 编程。开发人员不必学习 JavaScript 或客户端 Microsoft AJAX Library。同样,他们也不会受到 XML Script 或浏览器 DOM 的任何影响。
将传统的 ASP.NET 页面转换为 AJAX 页面需要进行两步操作。首先将 ScriptManager 控件添加到页面中。然后使用 UpdatePanel 控件封装任何想要部分刷新和异步刷新的控件组。UpdatePanel 控件支持嵌套,可以动态创建。此外,ASP.NET 页面可包含的 UpdatePanel 控件数目不受限制,可以是任意数量。
以下两种情况会触发实际更新:子控件回发时,以及发生特定外部事件时。通过触发器和其他属性,可以使每个 UpdatePanel 控件有条件地刷新内容。
使用 UpdatePanel 控件,您可以将 ASP.NET 页面逐步迁移到 AJAX,并且迅速完成此操作。实际上,同一个 ASP.NET 页面既可以使用 AJAX 式回发,也可以使用传统式回发。因此,UpdatePanel 必须随每个请求改变页面的视图状态。具体来说,就是将视图状态发送到服务器,更新视图状态以反映对选定控件的更改,然后将视图状态下载到客户端。对于事件 验证数据也会执行同样的操作。在客户端上不能更新视图状态和事件验证数据。因此,必须将视图状态和事件验证数据发送回服务器,检查是否已更改并做适当的更 新。在 AJAX 式和传统式回发中,要在实现成功回发的同时维护页面状态的一致性,则客户端一定要具有视图状态和事件验证数据的最新副本。
从根本上来说,UpdatePanel 是学习 ASP.NET AJAX 的最简单方法,它涉及的升级和迁移工作最少,并且可在传统页面和 AJAX 页面之间进行完全的互操作。当您使用可更新面板时,页面刷新会更迅速。有时,更新的速度甚至会快得用户根本无法意识到。因此,显示运行情况的面板将会非常 繁忙,但可能仍不够用。诸如 UpdateProgress 控件的繁忙面板主要用于长期任务,而不是让用户了解所显示内容进行了哪些更改。若要为用户提供有关此类更改的反 馈,UpdatePanelAnimation 扩展器(在 AJAX Control Toolkit 的最新 CTP 中定义)是一款更好的工具。您可以查看正在运行的示例。扩展器以动画效果显示回发期间 UpdatePanel 所包含的区域。另外,您还可以在扩展器上为正在更新和已更新事件指定动画效果。但是,请注意,您必须单独安装 AJAX Control Toolkit,因为它没有整合到 ASP.NET AJAX Extensions 下载包中。
控制频带外调用
如果您很擅长 JavaScript,并想要尝试从客户端直接调用服务器,那么您一般可使用下列两种方法:使用 Web 服务和调用静态页面方法。
通过在脚本管理器上注册 ASMX Web 服务,指示 ASP.NET AJAX 基础结构生成 JavaScript 代理类并将其注入客户端页面。若要查看代理类,可在地址栏(本地计算机)中键入 Web 服务的 URL,随后键入 /js 后缀。下面是一个 Web 服务的 JavaScript 代理的示例,其中有两个公共方法。为便于阅读,代码已进行了简化:
Type.registerNamespace('Samples.MyWebService');
Samples.MyWebService = new function()
{
this.appPath = "http://YourServer/AjaxDemo/";
var cm = Sys.Net.ServiceMethod.createProxyMethod;
cm(this, "LookupCustomer", "id");
cm(this, "LookupAllCustomers");
}
可使用此代码从脚本标记调用 Web 服务。它使用传统的代理模式,整体机制与您在服务器的传统 ASP.NET 或 Windows 应用程序中使用 Web 服务时的机制完全相同。
但是,仍有一些需要注意的问题。您想从客户端调用什么类型的服务器端代码?或者从另一个角度,您想从客户端调用 Web 服务的什么类型的操作?从 AJAX 页面调用的 Web 服务会将一些业务逻辑暴露给客户端页面。可以从 Internet 调用 Web 服务的公共端点,并且没有任何内置安全层可对应用程序逻辑提供保护。这个漏洞早已为人所熟知。
ASP.NET AJAX 为开发人员提供了通过 Web 服务公开某些应用程序逻辑的能力。一旦在 Internet 上发布,该逻辑(不受任何安全层保护)就可供任何调用者使用。一般来说,您应只公开那些能够在 Internet 中安全使用的数据和逻辑。如果您只是编写和调用返回产品目录的 Web 服务,可能不会产生任何实际问题。但公开业务逻辑层 (BLL)(例如信用卡验证过程)就不是您应该做的事了。
ASP.NET AJAX 会导致您使用 Web 服务向客户端页面公开 BLL,以供直接使用。您应将 AJAX Web 服务视为一种不重要的用户界面层 BLL。任何真正敏感的 BLL 块都应该使用传统的回发或 UpdatePanel 控件进行调用。
若要将 Web 服务直接链接到 ASP.NET AJAX 页面,这些 Web 服务必须是本地 Web 服务,驻留在与调用者页面相同的 Web 应用程序中。之所以这样要求,有两个原因。第一,Web 服务必须由知道如何处理每个请求上所附加 /js 后缀的 ASP.NET AJAX 应用程序支持。但是,您也可以使用其他 ASP.NET AJAX 应用程序来托管 Web 服务。在这种情况下,您的客户端调用可能会与当前浏览器中较严格的安全设置(防止跨站点调用)冲突。
页面方法与 Web 服务方法
将服务器代码与 ASP.NET AJAX 页面绑定的另一种方法是调用页面方法。可调用的页面方法是一种公共静态方法(在 Visual Basic? .NET 中为共享方法),这种方法在源代码类中定义,并使用 Web 服务方法所用的 WebMethod 属性进行修饰。目前,这仅限于 ASPX 页面 – 包括内嵌式代码和源代码 - 但将来可能扩展到用户控件和自定义控件。
我应特别指出,ASMX Web 服务和页面方法需要不同的设置。特别地,您必须在脚本管理器中注册 Web 服务,您还必须安装脚本 HTTP 模块,才能运行页面方法。图 3 显示 web.config 文件中所需的内容。
Figure3ASP.NET AJAX 的 Web.config 中的更改
<microsoft.web>
<scripting>
<webServices>
...
</webServices>
</scripting>
</microsoft.web>
<system.web>
<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx"
type="Microsoft.Web.Script.Services.ScriptHandlerFactory"
validate="false"/>
</httpHandlers>
<httpModules>
<add type="Microsoft.Web.UI.ScriptModule" name="ScriptModule"/>
</httpModules>
</system.web>
为了注册 Web 服务和强制生成代理,您需要执行下面的代码:
<asp:ScriptManager ID="scriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/WebServices/MyDataService.asmx" />
</Services>
</asp:ScriptManager>
此外,还需要其他属性来修饰 Web 服务类。尤其是,要生成 JavaScript 代理类,需要 ScriptService 属性;而对您计划使用的每个自定义类型(泛型类型除外),则需要 GenerateScriptType 属性。图 4 显示了一个示例。
Figure4ASP.NET AJAX Web 服务方法
namespace Samples
{
[WebService(Namespace = "http://samples.ajax/")]
[ScriptService]
[GenerateScriptType(typeof(Customer))]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class MyDataService : System.Web.Services.WebService
{
public MyDataService() {}
[WebMethod]
public Customer LookupCustomer(string id)
{
return CustomerManager.Load(id);
}
[WebMethod]
public CustomerCollection LookupAllCustomers()
{
return CustomerManager.LoadAll();
}
}
对于 Customer 类型,必须应用 GenerateScriptType;但对于从泛型 Collection<T> 类派生而来的 CustomerCollection,则不必应用,因为 ASP.NET AJAX 对该类型有内置支持:
public class CustomerCollection : Collection<Customer> {}
页面方法需要的 HTTP 模块联系 ASPX 请求的默认 HTTP 处理程序,并将呈现阶段重定向到执行特定方法并序列化返回值的自定义代码片段。
页面方法和 Web 服务方法这两种方法都帮助您访问后端 BLL。类似公开的 Web 服务方法,页面方法可以轻松地从浏览器的地址栏自动执行 – 这只需一些基本的 JavaScript Object Notation (JSON) 技能。因此,考虑到所要公开的 BLL 逻辑,您应象使用 WebMethods 一样小心使用页面方法。
最后,您是选择使用页面方法还是选择使用 Web 服务方法其实只是个人喜好而已。在这两种情况下,您都应生成一个外层,该层会在稍后路由到适当的 BLL 函数,如图 5 所示。只要您在每个页面中注册了服务的端点,就可以从任何页面调用 Web 服务方法。页面方法则只能从定义该方法的页面调用。目前,我个人更偏好使用页面方法。
图 5页面方法和 Web 服务方法的比较
ASP.NET AJAX Web 服务方法和页面方法都广泛使用 JSON 传送对象数据。作为轻量级数据交换格式,JSON 用于将对象序列化为字符串。由于其固有的简单性,JSON 既适合人类也适合计算机。能够读写 JSON 字符串的人要多于能够读写 SOAP 数据包的人。并且 JSON 也非常易于计算机解析和处理。
您可能会认为页面方法比 Web 服务的性能更高。毕竟,为了解析 Web 服务调用,ASP.NET 运行时必须解析 SOAP 数据包。但这并不完全正确。ASP.NET AJAX 会安装一个用于截取所有 ASMX 请求的定制的 HTTP 处理程序(请参阅图 3)。带有 /js 后缀的请求的处理方式不同,这些请求是直接与 JSON 负载及 Web 服务方法一起处理。因此,无论如何都不会包含任何 SOAP,请求的正文也只包含输入参数的 JSON 数据流。对于非 AJAX 请求,新 HTTP 处理程序只需将调用委托回理解 SOAP 的初始 ASP.NET 处理程序。
我实现 ASP.NET AJAX 的方法
考虑了所有因素后,我认为 UpdatePanel 是大多数开发团队可采用的最佳方法。它不排斥传统的 ASP.NET,因此您可以方便地修改现有页面。它也不复杂陌生,使用前不需要学习大量新知识。另外,UpdatePanel 能够为 BLL 提供与传统网页相同的保护级别,并且它完全支持运行冗长任务的异步 ASP.NET 页面。
最后一条忠告:避免混合使用各种 AJAX 平台。对于 JavaScript 内置对象扩展,ASP.NET AJAX 和其他框架之间可能会有冲突。更重要的是,不保证现在起作用的产品组合将来仍能使用。任何框架的任何新版本都可能引起新的冲突。
DBUtility 数据库访问组件基础类
二、项目引用关系
1、Web 引用 BLL。
2、BLL 引用 IDAL,Model,使用DALFactory创建实例。
3、IDAL 引用 Model。
4、Model 无引用。
5、DALFactory 引用IDAL,通过读取web.config里设置的程序集,加载类的实例,返回给BLL使用。
6、SQLServerDAL 引用 Model和IDAL,被DALFactory加载的程序集,实现接口里的方法。
三、实现步骤
1、创建Model,实现业务实体。
2、创建IDAL,实现接口。
3、创建SQLServerDAL,实现接口里的方法。
4、增加web.config里的配置信息,为SQLServerDAL的程序集。
5、创建DALFactory,返回程序集的指定类的实例。
6、创建BLL,调用DALFactory,得到程序集指定类的实例,完成数据操作方法。
7、创建WEB,调用BLL里的数据操作方法。
(三)、实现步骤
1、新建一个空解决方案后,添加一个空文件夹(可随意命名),然后再在此解决方案中添加各个类库项目和网站
2、新建一个类库项目(Model),设置程序集名称、默认命名空间、程序集签名。
3、设计Model类库中的类(实现序列化,[Serializable])。因为Model组件中主要是数据实体对象,所以类成员主要是一些私有字段、属性和构造函数。
4、修改AssemblyInfo.cs文件,记录此程序集的信息。
5、新建一个类库项目(IDAL),设置程序集名称、默认命名空间、程序集签名。
6、添加对PetShop.Model.dll程序集的引用。
7、设计IDAL类库中的接口。
8、修改AssemblyInfo.cs文件,记录此程序集的信息。
9、重复5-8的步骤,创建SQLServerDAL类库项目,实现IDAL接口里的方法。
tips:给Model类库中的类命名最好在后面加上Info,例如:CategoryInfo.cs
给IDAL类库中的类命名时,最好在前面加上I,例如:ICategory.cs
给SQLServerDAL类库中的类命名时,可什么都不加,例如Category.cs
这样,当这些类名都在SQLServerDAL类库中出现时,不用在类名前加命名空间限定就能区分开了。
10、新建一个Web项目,引用SQLServerDAL的程序集,并在web.config文件的appSettings配置段里添加键值对,<add key="WebDAL" value="PetShop.SQLServerDAL"/>
11、创建DALFactory类库项目,只需创建一个DataAccess类,创建私有静态只读字段,存储通过web.config文件 获得的对SQLServerDAL程序集的引用路径("WebDAL")。创建DataAccess类的静态构造函数。创建一个公共静态方法,返回程序集 指定类的实例。
12、创建BLL类库项目,设计相关业务逻辑类,调用DALFactory的静态方法,得到程序集指定类的实例,完成数据操作方法。
13、在Web项目中,设计表现层,并通过调用BLL里的数据操作方法获取数据。
注意:
1、web.config里的程序集名称必须与SQLServerDAL里的输出程序集名称一致。
2、DALFactory里只需要一个DataAccess类,可以完成创建所有的程序集实例。
3、项目创建后,注意修改各项目的默认命名空间和程序集名称。
4、注意修改解决方案里的项目依赖。
5、注意在解决方案里增加各项目引用。
在网页制作中,有许多的术语,例如:CSS、HTML、DHTML、XHTML等等。在下面 的文章中我们将会用到一些有关于HTML的基本知识,而在你学习这篇入门教程之前,请确定你已经具有了一定的HTML基础。下面我们就开始一步一步使用 DIV+CSS进行网页布局设计吧。
所有的设计第一步就是构思,构思好了,一般来说还需要用PhotoShop或FireWorks(以下简称PS或FW)等图片处理软件将需要制作的界面布局简单的构画出来,以下是我构思好的界面布局图。
下面,我们需要根据构思图来规划一下页面的布局,仔细分析一下该图,我们不难发现,图片大致分为以下几个部分:
1、顶部部分,其中又包括了LOGO、MENU和一幅Banner图片;
2、内容部分又可分为侧边栏、主体内容;
3、底部,包括一些版权信息。
有了以上的分析,我们就可以很容易的布局了,我们设计层如下图:
根据上图,我再画了一个实际的页面布局图,说明一下层的嵌套关系,这样理解起来就会更简单了。
DIV结构如下:
│body {} /*这是一个HTML元素,具体我就不说明了*/
└#Container {} /*页面层容器*/
├#Header {} /*页面头部*/
├#PageBody {} /*页面主体*/
│ ├#Sidebar {} /*侧边栏*/
│ └#MainBody {} /*主体内容*/
└#Footer {} /*页面底部*/
至此,页面布局与规划已经完成,接下来我们要做的就是开始书写HTML代码和CSS。
接下来我们在桌面新建一个文件夹,命名为“DIV+CSS布局练习”,在文件夹下新建两个空的记事本文档,输入以下内容:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>无标题文档</title>
<link href="css.css" rel="stylesheet" type="text/css" />
</head>
<body>
</body>
</html>
这是XHTML的基本结构,将其命名为index.htm,另一个记事本文档则命名为css.css。
下面,我们在<body></body>标签对中写入DIV的基本结构,代码如下:
<div id="container">[color=#aaaaaa]<!--页面层容器-->[/color]
<div id="Header">[color=#aaaaaa]<!--页面头部-->[/color]
</div>
<div id="PageBody">[color=#aaaaaa]<!--页面主体-->[/color]
<div id="Sidebar">[color=#aaaaaa]<!--侧边栏-->[/color]
</div>
<div id="MainBody">[color=#aaaaaa]<!--主体内容-->[/color]
</div>
</div>
<div id="Footer">[color=#aaaaaa]<!--页面底部-->[/color]
</div>
</div>
为了使以后阅读代码更简易,我们应该添加相关注释,接下来打开css.css文件,写入CSS信息,代码如下:
/*基本信息*/
body {font:12px Tahoma;margin:0px;text-align:center;background:#FFF;}
/*页面层容器*/
#container {width:100%}
/*页面头部*/
#Header {width:800px;margin:0 auto;height:100px;background:#FFCC99}
/*页面主体*/
#PageBody {width:800px;margin:0 auto;height:400px;background:#CCFF00}
/*页面底部*/
#Footer {width:800px;margin:0 auto;height:50px;background:#00FFFF}
把以上文件保存,用浏览器打开,这时我们已经可以看到基础结构了,这个就是页面的框架了。
关于以上CSS的说明(详细请参考CSS2.0中文手册,网上有下载):
1、请养成良好的注释习惯,这是非常重要的;
2、body是一个HTML元素,页面中所有的内容都应该写在这标签对之内,我就不多说了;
3、讲解一些常用的CSS代码的含义:
font:12px Tahoma;
这里使用了缩写,完整的代码应该是:font-size:12px;font-family:Tahoma;说明字体为12像素大小,字体为Tahoma格式;
margin:0px;
也使用了缩写,完整的应该是:
margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px
或
margin:0px 0px 0px 0px
顺序是 上 / 右 / 下 / 左,你也可以书写为margin:0(缩写);
以上样式说明body部分对上右下左边距为0像素,如果使用auto则是自动调整边距,
另外还有以下几种写法:
margin:0px auto;
说明上下边距为0px,左右为自动调整;
我们以后将使用到的padding属性和margin有许多相似之处,他们的参数是一样的,
只不过各自表示的含义不相同,margin是外部距离,而padding则是内部距离。
text-align:center
文字对齐方式,可以设置为左、右、中,这里我将它设置为居中对齐。
background:#FFF
设置背景色为白色,这里颜色使用了缩写,完整的应该是background:#FFFFFF。
background可以用来给指定的层填充背景色、背景图片,以后我们将用到如下格式:
background:#ccc url('bg.gif') top left no-repeat;
表示:使用#CCC(灰度色)填充整个层,使用bg.gif做为背景图片,
top left
表示图片位于当前层的左上端,no-repeat表示仅显示图片大小而不填充满整个层。
top/right/bottom/left/center
用于定位背景图片,分别表示 上 / 右 / 下 / 左 / 中;还可以使用
background:url('bg.gif') 20px 100px;
表示X座标为20像素,Y座标为100像素的精确定位;
repeat/no-repeat/repeat-x/repeat-y
分别表示 填充满整个层 / 不填充 / 沿X轴填充 / 沿Y轴填充。
height / width / color
分别表示高度(px)、宽度(px)、字体颜色(HTML色系表)。
4、如何使页面居中?
大家将代码保存后可以看到,整个页面是居中显示的,那么究竟是什么原因使得页面居中显示呢?
是因为我们在#container中使用了以下属性:
margin:0 auto;
按照前面的说明,可以知道,表示上下边距为0,左右为自动,因此该层就会自动居中了。
如果要让页面居左,则取消掉auto值就可以了,因为默认就是居左显示的。
通过margin:auto我们就可以轻易地使层自动居中了。
5、这里我只介绍这些常用的CSS属性了,其他的请参看CSS2.0中文手册。
当我们写好了页面大致的DIV结构后,我们就可以开始细致地对每一个部分进行制作了。
在上一章中我们写入了一些样式,那些样式是为了预览结构而写入的,我们把css.css中的样式全部清除掉,重新写入以下样式代码:
/*基本信息*/
body {font:12px Tahoma;margin:0px;text-align:center;background:#FFF;}
a:link,a:visited {font-size:12px;text-decoration:none;}
a:hover{}
/*页面层容器*/
#container {width:800px;margin:10px auto}
样式说明:
a:link,a:visited {font-size:12px;text-decoration:none;}
a:hover {}
这两项分别是控制页面中超链接的样式,具体我就不说明了,请大家参阅手册。
#container {width:800px;margin:10px auto}
指定整个页面的显示区域。
width:800px指定宽度为800像素,这里根据实际所需设定。
margin:10px auto,则是页面上、下边距为10个像素,并且居中显示。
上一章中我们讲过,对层的margin属性的左右边距设置为auto可以让层居中显示。
接下来,我们开始制作TOP部分,TOP部分包括了LOGO、菜单和Banner,首先我们要做的就是对设计好的图片进行切片,以下是在FW下完成的切片:
我将TOP部分切片为两部分,第一部分包括了LOGO和一条横线。由于LOGO图片并没有太多的颜色,这里我于是将这一部分保存为GIF格式,调色 板选择为精确,选择Alpha透明度,色版为白色(此处颜色应与背景色相同),导出为logo.gif,图像宽度为800px。
到这里,有的朋友就说了,* 为什么要使用GIF格式?使用JPEG不是更好吗?
因为GIF格式的图片文件更小,这样能使页面载入的速度更快,当然使用此格式之前必须确定图片并没有使用太多的颜色,当我们使用了GIF格式时,从肉眼上并不能看出图片有什么太大的变化,因此这是可行的。
* 接下来的Banner部分还能使用GIF格式吗?
答案是不能,因为Banner部分是一个细致的图片,如果使用GIF格式颜色会有太大的损失,所以必须使用JPEG格式,将文件导出为banner.jpg。
* 合理的切片是非常之重要的,因为切片的方法正确与否决定了CSS书写的简易程度以及页面载入速度。
切好片后,我们还需要对TOP部分进行分析并将DIV结构写入Header中代码如下:
<div id="menu">
<ul>
<li><a href="#">首页</a></li>
<li class="menuDiv"></li>
<li><a href="#">博客</a></li>
<li class="menuDiv"></li>
<li><a href="#">设计</a></li>
<li class="menuDiv"></li>
<li><a href="#">相册</a></li>
<li class="menuDiv"></li>
<li><a href="#">论坛</a></li>
<li class="menuDiv"></li>
<li><a href="#">关于</a></li>
</ul>
</div>
<div id="banner">
</div>
为什么要这么写呢,因为对菜单使用列表<li>形式,可以在以后方便对菜单定制样式。
而为什么要添加以下代码呢?
<li class="menuDiv"></li>
插入这一段代码是可以方便地对菜单选项之间插入一些分隔样式,例如预览图中的竖线分隔。
然后我们在css.css中再写入以下样式:
/*页面头部*/
#header {background:url(logo.gif) no-repeat}
样式说明:
#header {background:url(logo.gif) no-repeat}
给页面头部分加入一个背景图片LOGO,并且不作填充。
这里,我们没有指定header层的高度,为什么不指定呢?
因为header层中还有菜单和banner项,所以层的高度暂时是未知的,而层的属性又可以让层根据内容自动设定调整,因此我们并不需要指定高度。
使用列表<li>制作菜单
开始此节的学习前,请确认你已经参照之前的几节内容写入了DIV、CSS到index.htm和css.css文件中。
这一节我将告诉大家如何用列表<li>来制作菜单。
<div id="menu">
<ul>
<li><a href="#">首页</a></li>
<li class="menuDiv"></li>
<li><a href="#">博客</a></li>
<li class="menuDiv"></li>
<li><a href="#">设计</a></li>
<li class="menuDiv"></li>
<li><a href="#">相册</a></li>
<li class="menuDiv"></li>
<li><a href="#">论坛</a></li>
<li class="menuDiv"></li>
<li><a href="#">关于</a></li>
</ul>
</div>
以上是这部分的结构,有关于<ul></ul>、<li></li>这两个HTML元素大家自己去参考相关的内容吧,它们最主要的作用就是在HTML中以列表的形式来显示一些信息。
还有一点需要大家一定要分清楚的,当在HTML中定义为id="divID"时,在CSS对应的设置语法则是#divID{} ,如果在HTML中定义为class="divID"时,则在CSS中对应的设置语法是.divID。
如果id="divID"这个层中包括了一个<img></img>,则这个img在CSS中对应的设置语法应该是#divID img {},同样,如果是包含在class="divID"这个层中时,则设置语法应该是.divID img {},这一点希望大家要分清楚了。
另外,HTML中的一切元素都是可以定义的,例如table、tr、td、th、form、img、input...等等,如果你要在CSS中设置它们,则直接写入元素的名称加上一对大括号{}就可以了。所有的CSS代码都应该写在大括号{}中。
按照上面的介绍,我们先在css.css中写入以下代码:
#menu ul {list-style:none;margin:0px;}
#menu ul li {float:left;}
解释一下:
#menu ul {list-style:none;margin:0px;}
list-style:none,这一句是取消列表前点,因为我们不需要这些点。
margin:0px,这一句是删除UL的缩进,这样做可以使所有的列表内容都不缩进。
#menu ul li {float:left;}
这里的 float:left 的左右是让内容都在同一行显示,因此使用了浮动属性(float)。
到这一步,建议大家先保存预览一下效果,我们再添加下面的内容,效果如下:
这时,列表内容是排列在一行,我们在#menu ul li {}再加入代码margin:0 10px
#menu ul {list-style:none;margin:0px;}
#menu ul li {float:left;margin:0 10px}
margin:0 10px的作用就是让列表内容之间产生一个20像素的距离(左:10px,右:10px),预览的效果如下:
现在,雏形已经出来了,我们再来固定菜单的位置,把代码改成如下:
#menu {padding:20px 20px 0 0}
/*利用padding:20px 20px 0 0来固定菜单位置*/
#menu ul {float:right;list-style:none;margin:0px;}
/*添加了float:right使得菜单位于页面右侧*/
#menu ul li {float:left;margin:0 10px}
这时,位置已经确定了,可是构思图中,菜单选项之间还有一条竖线,怎么办呢?
别忘了,我们早就已经留好了一个空的<li class="menuDiv"></li>,要想加入竖线就使用它了。
按照上面说的方法,我们再添加以下代码:
.menuDiv {width:1px;height:28px;background:#999}
保存预览一下,竖线是否已经出来了?关于这段代码就不多讲了,应该是很容易理解的。
不过,菜单选项的文字却在顶部,我们再修改成以下代码:
#menu ul li {float:left;margin:0 10px;display:block;line-height:28px}
关于display:block;line-height:28px大家可以去参阅一下手册,我就不多讲了。
效果基本上已经实现了,剩下的就是修改菜单的超链接样式,在css.css中添加以下代码:
#menu ul li a:link,#menu ul li a:visited {font-weight:bold;color:#666}
#menu ul li a:hover{}
这个也不多说了,没什么好说的了,最后的效果如下:
这一节里面,主要就是想告诉大家如何使用好border和clear这两个属性。
首先,如果你曾用过table制作网页,你就应该知道,如果要在表格中绘制一条虚线该如何做,那需要制作一个很小的图片来填充,其实我们还有更简单的办法,只要在<td></td>中加入这么一段就可以了,你可以试试:
<div style="border-bottom:1px dashed #ccc"></div>
大家可以再次参考手册,然后你就能明白dashed、solid、dotted...等的作用,利用它们你可以制作出许多效果来,实线、虚线、双线、阴影线等等。
<div id="banner"></div>
以上代码便可以实现设计草图中的banner,在css.css中加入以下样式:
#banner {
background:url(banner.jpg) 0 30px no-repeat; /*加入背景图片*/
width:730px; /*设定层的宽度*/
margin:auto; /*层居中*/
height:240px; /*设定高度*/
border-bottom:5px solid #EFEFEF; /*画一条浅灰色实线*/
clear:both /*清除浮动*/
}
通过border很容易就绘制出一条实线了,并且减少了图片下载所占用的网络资源,使得页面载入速度变得更快。
另一个要说明的就是clear:both,表示清除左、右所有的浮动,在接下来的布局中我们还会用这个属性:clear:left/right。在这里添加clear:both是由于之前的ul、li元素设置了浮动,如果不清除则会影响banner层位置的设定。
<div id="pagebody"><!--页面主体-->
<div id="sidebar"><!--侧边栏-->
</div>
<div id="mainbody"><!--主体内容-->
</div>
</div>
以上是页面主体部分,我们在css.css中添加以下样式:
#pagebody {
width:730px; /*设定宽度*/
margin:8px auto; /*居中*/
}
#sidebar {
width:160px; /*设定宽度*/
text-align:left; /*文字左对齐*/
float:left; /*浮动居左*/
clear:left; /*不允许左侧存在浮动*/
overflow:hidden; /*超出宽度部分隐藏*/
}
#mainbody {
width:570px;
text-align:left;
float:right; /*浮动居右*/
clear:right; /*不允许右侧存在浮动*/
overflow:hidden
}
为了可以查看到效果,建议在#sidebar和#mainbody中加入以下代码,预览完成后可以删除这段代码:
border:1px solid #E00;
height:200px
保存预览效果,可以发现这两个层完美的浮动,在达到了我们布局的要求,而两个层的实际宽度应该 160+2(border)+570+2=734px,已经超出了父层的宽度,由于clear的原因,这两个层才不会出现错位的情况,这样可以使我们布局 的页面不会因为内容太长(例如图片)而导致错位。
而之后添加的overflow:hidden则可以使内容太长(例如图片)的部份自动被隐藏。通常我们会看到一些网页在载入时,由于图片太大,导致布局被撑开,直到页面下载完成才恢复正常,通过添加overflow:hidden就可以解决这个问题。
CSS中每一个属性运用得当,就可以解决许多问题,或许它们与你在布局的页并没有太大的关系,但是你必须知道这些属性的作用,在遇到难题的时候,可以尝试使用这些属性去解决问题。
完成后资料
css