自己翻译的书(关于ASP.NET),希望对大家有帮助 (十一)

第三章动态网络应用程序概述

综述

现在你已经有了创建HTML页面的一些经验,你应该已经有点概念哪里以及为什么HTML不足够创建应用程序。HTML用于创建信息页面是完全足够的,但是它缺少让应用程序变得——交互地——对用户有趣的性质。应用程序响应用户动作和输入。HTML文件可以相应某些操作——例如,点击一个链接或者图片的某个区域——但是那就是HTML的交互的限制。如果你想要做更多并且更多样化的相应用户行为和输入,你需要一种编程语言。HTML不是编程语言;它就是一个格式化语言。

在浏览器中有两处可以和用户交互来浏览网页。当用户改变页面时,你可以和日期交互;你可以使用运行在服务器端的代码来做这些,叫做服务器端代码(Server-side Code)。你也可以通过在浏览器本身防止代码来和用户交互。这叫做客户端代码(Client-side Code)。不幸的是,你(还)不能用相同的语言写客户端和服务器端代码因为一些浏览器只支持脚本语言——JavaScript。相反,使用经典ASP,开发者可以用VBScript实现大部分服务器端代码;现在,使用ASP.NET,大部分人选择使用C#或者是VB.NET。你还是有一个选择可以使用相同的语言实现在客户端和服务器端代码:JScript。可惜的是,Jscript是一个在.NET框架中的“第二层”语言,这意味着你会消耗大部分NET资源,但还是不能完全创建它们。

                小窍门: 在将来,当.NET框架在客户端机器上变得越来越普通,你可能可以使用C#来创建只针对于IE的应用程序。

当你学习书写动态网络应用程序是,在脑中清楚客户端和服务器端代码的不同是很重要的,因为这是一个对于初始开发者很容易弄混的概念。我经常阅读注释并且自问为什么“我的浏览器不能运行ASP.NET页面!”就好象错误的原因是ASP本身一样。从浏览器的角度看,根本就ASP.NET页面这种东西——只有HTML和脚本,并且被ASP.NET页面产生的内容,被CGI脚本产生的内容或者是简单来自静态HTML文件的内容都是没有任何区别的。如果你的浏览器并不支持ASP页面,你的页面会产生对于该浏览器不合法的内容——但这并不是浏览器的错。

弄清楚动态HTML(DHTML)和动态网络页面也是很重要的。记住,DHTML是一种客户端的改变页面显示和内容的方法。在DHTML中,你可以在页面中使用脚本和CSS样式,或者是——更可能的——两者的组合,来操作元素。相反,动态网络页面是一种部分或者全部内容还没有存在于HTML表格中的页面;服务器会通过代码来创建页面。换句话说,它会动态的创建页面。这并不神秘。浏览器会期望在响应中包含文字,HTML标签和脚本的字符串,只要字符串包含合法的文字,HTML以及脚本,浏览器就会正常显示。

什么是动态网络应用程序?

动态网络应用程序是一组在一起合作从而来创作一种用户在操作一个独立程序的假象的程序。例如,想象一个典型的数据驱动的应用程序。用户登录并且选择一些参数——也许是从列表中选择一个客户名——从而来生成报表来显示该客户的购买记录。用户可以通过选择一个特定的顺序来继续钻研数据或者是选择一个用户购买的产品来看该账单的细节,例如购买地,运输方式,或者是运输日期。当你写一个像这样的独立的窗口应用程序,你可能需要计划并且把它写成一个单独的程序。程序可能有多个模块或者是多个表单和类,但是它有一个确定的开头和结尾——用户启动应用程序,用一阵子,然后关闭应用程序。当用户在使用程序时,你——作为应用程序开发者——可以控制用户能够怎样操作应用程序。

例如,你可以在核心操作时让离开 (Exit)按钮失效来保证用户不会在一个不适当的时机离开程序。在登录之后,用户不能在没有退出的情况下就重新登录并且重启程序因为在用户被授权之后,你不能再提供对于登录表单的访问。在数据输入应用程序,在填写了表单之后,用户不能退回到那个表单并且不经过一系列应用程序设计者预定义的操作来改变数据——选择一个记录然后弹出来编辑它。用户甚至不能在没有通知你的情况下退出应用程序除非关掉计算机电源。在窗口应用程序中,这种控制是已存在的——你不需要自己实现。

在动态网络应用程序中,你没有那种自由。用户操作会发生在不同于你应用程序运行的机器的另一台机器上。因此,你的应用程序不知道也不可能控制用户在做什么;你必须在不能控制这些操作的情况下来让程序正常运行。你可以使用客户端脚本来观察和控制一些用户操作,但是其他的操作会不能被脚本所控制。例如,每一个浏览器都有一个后退(Back)按钮。想象一下你有一个让用户填写的表单。用户填好后会点击提交(Submit)按钮,然后你会把数据写到数据库中。你会返回下一个页面给用户。

现在假设用户按了后退按钮。这不会向你的应用程序发送信息(因为浏览器会从缓存中加载页面)。现在用户会改变表格内容并且再次点击提交按钮。你当然不想再创建另一条记录,并且,依赖于应用程序,你可能甚至不想重写当前记录。这并不是一个不正常的现象——你需要在你的网络应用程序中计划并且限制这种事情。

这有另一种常见的情况。用户登录应用程序并且操作一会儿,但是然后他转换了想法并且在浏览器窗口输入另一个网站的URL。最后,用户会关掉浏览器并且离开机器。问题是:从应用程序角度讲,你怎样处理这个?记住,你可能已经在服务器上为用户存储了数据。那你怎么才能知道是否用户还在和你的应用程序交互呢?简单的答案就是:你不能。相反,对于核心数据,每当数据改变,你就应该把数据存储到磁盘上;对于非核心数据,在一段特定时间后,你可以抛弃它——这个时间的值可以针对用户和应用程序独立设置,叫做HttpSessionState.Timeout,通常它有一个更短的名字,叫做Session.Timeout

最后,网络应用程序和标准的可执行程序间有一个主要的区别。在关掉浏览器并且离开之前,假设在当前的应用程序中,最后一段的用户给当前页面加上了标签。很久之后(在Session.Timeout发生之后),用户会登录并且点击该书签。那你的应用程序该如何相应呢?再者,这是一个极其平常的并且你必须预料到的问题不然你的应用程序一定会有位呢提。不像是标准应用程序,你没办法直接控制这问题——你不能组织用户创建数据并且组织用户在之后任何时间访问它。然而,你可以控制在你的应用程序收到无法预料的请求时该如何处理。例如,你可以直接把用户转到应用程序的第一页。如果你的应用程序非常友好,你应该在用户重新登录时就恢复用户的状态。

在这章的开始,我提到网络应用程序是一组程序,不是一个程序。那是因为在一个事务应用程序中,就像是网络应用程序,你不能依赖传统的数据存储技术来创建一个有粘性的应用程序。相反,你可以再细想一下,每一个都不是连续的。当你使用C#网络应用程序,你会学着把动态网络应用程序看作是一系列浏览器和服务器的事务。编写单个事务处理程序是非常直接的。让单个应用程序表现得像是一个大的整体的一部分是非常有挑战性的。

什么是数据驱动的应用程序?

你应该经常听到“数据驱动站点(Data-driven Site)”这个名词——我已经在这章使用过它。那它到底是什么意思呢?难道不是所有的应用程序都是数据驱动的么?因为所有的程序不都是从服务器下载数据然后把它发送到浏览器么?是的,但是这无关紧要。数据驱动的应用程序从数据源或者是外部数据源为用户提供数据。那意味着应用程序必须可以读(通常是写)到外部数据源的数据并且提供数据验证(Data Validation),数据缓存(Data Caching)以及数据翻译(Data Translation)的需求。

另外,数据驱动的应用程序通常会随着时间增长。即使是维护一个到实事通讯(Newsletter)的订阅列表(Subscriber)的应用程序也必须仔细计划和实现以保证它可以不仅仅是可以操作最开始的小数据,也可以操作积累了几年的数据。写一个操作100个记录的应用程序相对简单,但是写一个能操作100或者100000条记录的应用程序就比较难了。当你允许多个用户同时操作时,应用程序的复杂性会更加增长的。尽管这本书不准备提到所有在创建数据驱动应用程序时遇到的所有问题,你还是会看到怎样设计并且实现数据应用接口,并且你将会使用ADO.NETSQL SERVER在外部关系数据库中来创建,传输和更新信息。

我为什么需要使用HTML模板和CSS

正像你已经发现的那样,如果你想要重复地创建相同类型的表格,你就需要不停的重复创建相同类型的HTML页面。并且,一种帮助你设计粘性好的网络应用程序的方法就是仔细地设计用户接口以使得你需要对每个页面分别处理。你可以通过为你的“破”数据创建模板来实现。把用户接口(也就是模板)和数据分离开来需要自己计划,但是这也使得你的网站很容易被更新和维护。

例如,当你创建一个企业网络入口(Corporate Web Portal),你可能决定把部门列在页面最上面,每一个都以下拉菜单的方式实现。你可以把HTML,事务处理代码以及数据放到应用程序的每个页面,但是当一个部门增加了一个题目或者是你的公司分隔或者组合部门时,那又该怎么办呢?如果你把代码放到每个单独的页面,你必须改变每一个页面。这是一个典型的从小开始然后逐渐增长的例子。开发者,可以使用HTML编辑器或者是文字编辑器手动的维护20-30个页面,但是当页面增长到200或者是300页面时,就不可能这样维护数据了。

对于这个问题的答案(以及对于很多其他的编程问题)就是提供一个间接的层来把最顶端的菜单代码放到单独的文件中。IIS支持#inlcude命令,这个命令可以用另一个文件的内容来替换命令本身。例如,假设文件topmenus.asp包含菜单的HTML代码以及客户端脚本。除了把.asp文件中的内容拷贝到你应用程序的每个页面,你只需要在每个页面放置一行命令。#include命令写作HTML注释。服务器不会理解命令而会忽略它们,然后把它们发送到浏览器,同时浏览器也会忽略因为它们是注释。例如,下面的代码会让IIStopMenus.asp的内容插入到每个页面:

<!-- #include file="topMenus.asp" -->

#inlcude命令中,文件topMenus.asp必须和请求页面在一个目录中。另一个能让你引用服务器任何位置的文件的格式是:

<!-- #include virtual="/includes/topMenus.asp" -->

代码中的关键字virtual告诉你在网络服务器上目录包含一个虚拟路径。

让这个类比再进一步,公司端口的设计者会遍历所有页面,移除菜单的代码和数据,并且用#include命令指向的另一个文件来替换原有文件,该文件包含所有需要的功能。但是然后(你可以猜到),有些事情变了。市场部发布了一个备忘录要求所有的商业公司通讯必须使用Verdana字体。当然,端口必须立刻改变因为它变成一个公司基础信息的可视化部分。作为一个端口开发者,你会有一个问题。你该怎么改变HTML页面中的所有myriad字体的标签?有个问题。应该说很难写出一个搜索和替换(Search-and-Replace)的代码来发现和改变所有别人设置的字体。

在这个发生之前,在第一时间做出计划避免这个问题。使用CSS样式表,为你的应用程序创建一组类style类型。你应该避免使用内联样式甚至是嵌入样式,除非必须如此。使用链接或者是导入样式表。就像是你在第二章“HTML基础”上讲到的,你可以在文档的<head>部分使用<link>标签来链接样式表;例如:

<link rel="stylesheet" type="text/css" href="mystyles.css">

我并不指望你在心里牢牢记住这句话,事实上,我会在本书中都这么做。我会告诉你一个秘密:你的网络应用程序越“动态(Dynamic)”,你越是在.NET类,外部CSS文件,#include文件,数据库文件,以及代码中更好的封装功能,当环境改变时,你会更容易适应。在一个位置改变代码比在很多位置改变代码要更容易,更不容易出错。

客户交互

动态网络应用程序意味着内容会因为某个原因改变。一个创建动态应用程序的原因就是数据库中的数据可能会改变。但是就像是通常那样,因为你想要相应单个用户的喜好或者是动作,所以你才开发动态应用程序。每一次用户从你的网站请求页面,你可以把它想成一个交互的几乎。每一次用户输入一个字符或者是移动鼠标,就是另一个交互的机会。用户以前访问过页面这个事实也提供了一个交互的机会。例如,如果你登录www.amazon.com并且买了一本或者多本书,当你一会儿登录那个页面的时候你会发现有一点不同。Amazon的工作人员仔细地追踪客户的习惯。通过这样,他们可以预测你未来的购买行为。如果你买了一本哈利波特,经验显示你非常有可能买另一本哈利波特并且你也可能从其他也购买哈利波特的人购买书的列表中选到另一本书。这门技术叫做个性化(Personalization)。必须承认,这是个性化的一个高级例子,但是这也是一些基本的想法,例如用名字欢迎用户(“欢迎回来,琼斯先生”)或者是保存用户的习惯。

我并没有推荐你在你写的每一个应用程序中都实现个性化;我是说个性化和交互是硬币的两面。个性化的要点是增加交互。当Amazon为你提供一个列表,你非常有可能买另一本书。相似的,当在你登录网站时,应用程序保存并且应用你的喜好,你更可能使用它。我保证你登录过那种需要你提交一个很长的表格的网站。当你最后写完并且提交表格后,网站(在一个延迟之后)返回给你一个错误信息(这个信息你通常需要滚动鼠标来找到),这告诉你写错了某些值。这就是一个不好的交互的例子。而且你非常可能不喜欢这种应用。相反,如果一个应用程序可以在你输入错误时立刻告诉你,并且告诉你为什么错了,并且把光标放在错误的输入框内——当需要时,主动滚动到该输入框——这样的应用程序更可能让你对于应用程序满意。

直到最近,在浏览器中提供一个真正的交互很难,因为浏览器本身并没有让你和用户交互的资源,除了最简单的一些。然而,IE,从版本4或者5以及更高的版本开始,提供了一组类似于窗口编程的事件。你可以侦测鼠标活动(事实上,浏览器提供了mouseEnter以及mouseOut时间,这些连Windows API都没有直接提供),点击,双击,以及拖拽操作。连同DHTML,客户端脚本,以及互联网服务,你可以创建用户接口——尽管不像是窗口表格——也非常有服务性。最后,因为.NET使得和服务器交互非常方便,你可以创建不使用窗口表单的C#应用程序。

网络应用程序vs网站

尽管名词网站以及网络应用程序一般可以互换,它们还是有不同的。网络应用程序不同于网站因为他们有不同目的。人们浏览网站,但是它们使用网络应用程序来完成任务。大部分网站是充满信息的。大部分网络应用程序不是。

当你在Yahoo! (www.yahoo.com)看体育版,你不是在完成任务;你是去获取信息的。通常你心里没有特定的信息——你仅仅是浏览。有时,很难区分应用程序和网站。例如,Expedia (www.expedia.com) 是一个你可以浏览,查找旅游信息,费用和飞行的网站,但是它也是一个可以买机票的地方。Expedia是一个包含嵌入式应用程序的网站的例子。

相反,大多数商业应用程序就不那么明显。当用户登录到公司应用来填写购买表单,它对浏览并没有什么兴趣;他想要尽快并且准确地完成订单。用户的目的和其他网站完全不同。

区别是重要的,因为它会影响——或者是应该影响你怎么创建用户接口,什么辅助和错误信息你应该提供,以及在应用程序中为每个用户你应该存储多少数据。

 

什么是数据?数据在哪里?

动态网络程序使用和存储数据。数据大部分放在数据库中以使得你可以提供最新的数据给客户端。在动态网站中,数据可以存在于缓存的HTML文件中,平面文件中,以及,越来越多的,在XML文件中。

数据库

关系数据库是非常方便的数据仓库因为它们可以几乎可以存储任何类型的数据,从比特(Bit)值到非常大的二进制或者是文本(二进制大对象——文本或二进制数据的长序列),并且他们也提供了大量的排序和过滤服务。

要明智的选择你的数据库。例如,不要使用一个像Access的文件数据库;使用像是SQL ServerOracleDB2SybaseMySQL,或者是Informix这样的完整的关系数据库。如果你没有这些数据库的完整拷贝,你可以使用MSDE或者是个人版Oracle。这些“轻量级(Light)”版本的功能和完整版本几乎一样除了他们会限制数据库大小和同步链接的数量(MSDE只允许5个同步链接)。因此,他们非常适合小量开发者和测试者的应用程序开发。我并不推荐使用这些小数据库部署应用程序,毕竟——它们不能支持足够的用户。

HTML文件

当你可以,在某种程度上,从HTML文件中存储和提取数据,他们对于存储模板和缓存数据非常有用。例如,假如你在一个数据库中为用户列表存储了“真的”数据。你可以在每次用户请求了一个显示列表的页面,你可以运行一个提取数据的请求。这是最简单的保证你可以获得最新的客户数据的方法。这也是对用户资源的一个不太好的使用。客户列表不会那么经常改变。请求数据库来满足每个请求意味着你在使用数据库连接,服务器内存,以及网络带宽来重复地提供相同的数据。

另一种提供完全相同的精确度的但是使用更少资源的方法就是在第一次页面请求时动态创建页面,然后把结果HTML页面写到磁盘上。对于接下来的请求,你可以从磁盘提供页面。

但是等一下!一旦数据库改变,难道不是意味着页面过时了么?是的,但是记住,你在创建一个动态应用程序。如果你的应用程序就是那个改变数据库的,你可以在数据改变时刷新页面。如果其他应用程序也可以改变数据库,你可以写一个触发器(Trigger)来刷新数据,写一个改变文件,或者是在表格中改变标记,这样你总是可以读到最新的数据。如果触发器写一个改变文件的入口,你可以检查文件的时间戳来决定是否要刷新数据。如果触发器改变了表格中的标记(Flag),你可以使用一个可以返回一个值来决定是否要刷新数据的程序。不管你使用什么方法,结果就是你几乎不需要从数据库获取完整的客户列表来满足请求。

平面(ASCII)文件

这么多年来,“平面文件”,或者是ASCII文件,是一个把数据在平台和应用程序见传输的方法。许多商业应用仍然会定期地从平面文件的主框架接受数据。它们现在没有那么有用,因为有许多其他的方法,你还是可能发现把文件放在平面文件中而不是数据库表格中更容易。例如,把字符串放到应用程序文件日志文件的后面比建数据库,决定需要的域,写存储步骤,以及建立一个类以及一些类来控制读写日志更加容易,尤其是你需要写日志仅仅是为了帮助你定位程序错误。

然而,因为如此多的信息在平面文件中,他们都是动态应用程序的资源。

XML文件

XML文件是平面文件的替代。尽管XML文件比平面文件低效,因为文件中的重复的标签,他们却非常好用。你不必写代码来解析文件,决定域名和域长度,并且检查文件尾或者是行尾标记。并且,你也可以以完全相同的方法读取包含任何类型数据的XML文件——使用XML解析器。但是解析器的能力不仅仅只是把文件中连续的记录和域分隔。解析器可以提取单个记录或者是域或者是像数据库那样排序和过滤信息,以及使用可扩展样式表语言转换(XSLT),他们可以把数据从一个格式转换成另一种格式。.NET框架会广泛的支持XML,所以在本书的后面你会看到更多这些内容。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值