knowledge base (kb) 中的一篇文章“q110264 info: microsoft consulting services naming conventions for visual basic”(英文)对命名约定提供了真知灼见。
尽可能采用目录结构为您的各个应用程序部件提供始终如一的位置。您应用程序的实际目录结构当然由您自己决定,但通常是将图像、文档、include 文件和组件分别放置在单独的目录中。以下是简单 asp 应用程序目录结构示例。
目录结构示例:
\simpleaspapp \docs \images \includes
一个好的目录结构允许您有选择地应用 ntfs 权限。您还可以从 asp 应用程序内部使用相对路径。例如,可以使用以下代码,从位于 simpleaspapp 目录的 default.asp 页,引用 includes 目录中的 include 文件 top.asp:
./includes/top.asp
注意我的 include 文件的扩展名是 .asp,而不是 .inc。这样做是出于安全方面的考虑,而且使用 .asp 扩展名(而不是 .inc),还能够在 visual interdev(r) 中使用彩色编码。
有关结构化 asp 应用程序的其他一些提示和技巧,请参阅文章“asp conventions”(英文)。
原则 2:设计为在服务下运行
asp 将在服务下运行。设计 asp 应用程序时,您马上会面临在桌面应用程序中不会遇到的安全环境和线程问题。在桌面环境中,通常只处理作为交互式用户运行的单线程执行,而且有权访问当前的桌面系统。在“internet 信息服务 (iis)”中,模拟不同用户环境的多个客户机线程调用您的应用程序,而且您的应用程序被限于“系统”桌面。
这对您来说意味着什么?请学习 iis 的安全模式。还要提醒您:仅因为某些东西能在 visual basic ide 下能够正常运行,并不意味着它就能在 asp 技术中安全运行。visual basic ide 并没有准确地模拟运行时环境。常见的设计错误包括:在 asp 技术中使用需要用户界面的 .ocx 控件,使用对线程来说不安全的组件,和使用要求特殊的用户上下文的组件。要避免的一个最简单的问题,就是从应用程序中试图访问 hkey_current_user (hkcu) 注册表项(例如,不要调用 visual basic 的 getsetting 和 savesetting 函数,它们都依赖于 hkcu)。同样,不要出现需要用户进行人机交互的消息框或其他对话框。
以下文章是有关 asp 技术中的安全和验证问题的相当不错的入门读物:
- “authentication and security for internet developers”(英文)
- “q172925 info: security issues with objects in asp and isapi extensions”(英文)
原则 3:封装业务逻辑
asp 技术通过生成 html 输出提供了表示服务。简而言之,它会生成用户界面。您需要将商务逻辑从 asp 表示脚本中分隔开来。即使您不使用 com 组件将业务逻辑从 asp 代码中分隔开来,至少也要将业务逻辑分隔到函数和 include 文件中,以提高可维护性、可读性和可重用性。在需要排除故障和隔离问题时,您还能体会模块化设计方法的好处。
调用脚本内部调用函数和方法,可避免代码乱作一团,并能在 asp 应用程序中添加结构。下面举例说明从 asp 代码中,将逻辑分离到方法调用中:
lt;% main() mybizmethod() ... sub main() getdata() displaydata() end sub %>
在使用包含 asp 功能的技术时,可以应用这一原则。下面举一个使用 visual basic webclass 时的例子,说明如何使用这一原则:
- 因为 webclass 本身引用 asp 代码生成 html,所以您不要将业务逻辑直接置于 webclass 内。因为这是您的表示层,不在 mts/com+ 下直接运行 webclass。
- 从 webclass,可以调用能运行在 mts/com+ 中的单独业务组件。
- 您可以决定创建自己的、具有对 asp 引用的 com 组件,而不是依赖于 webclass 框架结构和额外的 webclass 运行时开销 — 您也可以使用 asp 脚本直接将业务组件自动化。
原则 4:尽晚获取资源,尽早释放资源
常见的问题是,从桌面系统到服务器的过渡。许多具有桌面系统背景的开发人员从来没有为服务器的一些问题和资源共享担心过。在传统的桌面应用程序中,连接到服务器是个耗时的过程。为了改善用户的体验,通常采用尽早获取资源和推迟释放资源的方法。例如,许多应用程序会在它的整个运行时间内始终连接着数据库。
这种方式在传统的桌面应用程序中能够正常工作,其原因是用户数量非常明确,容易加以控制,并且后端与前端紧密连接。然而,对于当前的 web 应用程序,这种方式已经不可行了,其原因是有限的服务器资源将面对越来越多的用户。为了使您的应用程序能够应付用户的增加,您需要尽晚获取资源,尽早释放资源。
共用有助于增加这一方式的有效性。通过共用,多个用户能够共享资源,而且等待时间最少,对服务器的影响也最小。例如,在处理数据库时,odbc 连接共用和 oledb 资源共用可以实现从共用池中选择连接,最大程度地减少连接数据库的开销。
有关共用 ado 的详细信息,请参阅“pooling in microsoft data access components”(英文)。
原则 5:使用数据库维护复杂的状态
尽管 http 协议是无状态的,asp 开发人员还是会经常使用 asp 功能内置的状态保持机制。例如,使用 asp 技术内置的 application 对象,开发人员所保存的资源能够为应用程序的所有用户共享。通过使用 asp 内置的 session 对象,开发人员只为单个用户保存资源。
尽管听起来在 asp 技术的 session 对象中保存信息是一个非常方便的保持状态的方式,然而这一方式付出的代价太大,而且它也可能成为对可伸缩性的最大的限制因素之一。应用程序的可伸缩性本质上是随着用户数目的增长能够继续保持其性能的能力。而对于每一用户,在会话超时或被放弃之前,session 对象都会消耗服务器的资源。会话还会将您捆绑到一台服务器上,从而限制您利用 web 集群的功能。请尽可能不要使用 asp session 对象进行状态管理。如果您完全没有使用会话,您就可以禁用 web 应用程序的 session 状态(请参阅 iis 文档)。否则,您可以使用下述语句,针对每一页禁用 session 状态:
<%@enablesessionstate=false %>
对于一些简单的数据,您可以使用 querystring cookie 或隐藏的窗体域保持 asp 请求间的状态。然后,对于更为复杂的信息,通常推荐您使用数据库。一般所采用的方式是生成某一特有的标识符,然后发送到每一个发出请求的客户机,并保存为隐藏的窗体域。在随后的请求中,这一特有的标识符被用于在数据库中查找与该用户相关的状态信息。这一方式提供了更高的可伸缩性和更为简洁明了的代码。
有关使用 querystring cookie 和隐藏的窗体域的详细信息,请参阅“q175167 howto: persisting values without sessions”(英文)。
原则 6:使用 server.createobject 创建对象
在创建 asp 技术的对象时,您可以选择 <object> 标记、server.createobject 和 createobject 三种方式。每项技术的行为略有不同。尽管在 iis 4.0 中,使用 <object> 标记或 createobject 比 server.createobject 略具性能优势,我们一般还是推荐使用 server.createobject, 以便于 asp 应用程序认知您的对象。(注意在 iis 5.0 中,前两项与 server.createobject 相比,已经没有性能优势。)
<object> 标记仅在调用第一个方法时才会创建组件,因此能够节省资源。server.createobject 使用 asp 技术内置的 server 对象创建组件。实质上,它只是执行了 cocreateinstance,但是 asp 却能够认知这一对象。同时,还将调用 asp 技术的传统的 onstartpage 和 onendpage。(注意最好在 iis 4.0 或者更高版本中使用 objectcontext)。如果您只是使用 createobject,您将越过 asp 技术而直接使用 scripting 引擎。