ASP/IIS可安装组件一

作者:网络 来源:佚名 更新时间:2008-02-05 19:21:11 点击:


    asp/iis的标准安装包括一系列服务器组件,这些组件在iis文档中被描述为可安装组件(installable component),尽管缺省状态下它们是安全安装。但也有可能这个名称仅仅是沿用asp的前几个版本中的名字。在以前版本中,这些组件需要人工安装。现在,如果要给它们起个合适的名称,可称为“可实例化的组件”。
       需要注意的是,在第8章将介绍一个特定的可安装组件,即ado组件。后面的章节中使用的其他组件都是作为特定的服务或服务器应用程序的一部分而安装的。例如协作数据对象(collaborative date objects,简称cdo和cdonts)组件,用于邮件服务器和电子邮件消息。本章的其余部分将讨论,如何使用其他通用性较强的组件为web网站或intranet提供增强功能。
       在windows 2000中的winntsystem32intesrv目录下可找到这些asp可安装组件,该目录也放置一些组件要求的配置文件。下面按字母顺序列出了一些组件。
       · ad rotator组件用于控制可点击图像的出现,如广告或标题。使用存储在配置文件中的信息,ad rotator能够依据配置文件规定的比率显示不同的图像,同时也具备把可点击的广告重新定位到相应的url以及记录图像点击次数的特性。
       · browser capabilities组件使用useragent字符串,该字符串由浏览器发往服务器,用来识别相应的浏览器。它提供了反映特定浏览器功能的一系列属性,例如是否支持脚本、cookie或java小程序。
       · content linking组件用于提供一系列方便导航的页面,这些页面可被改变或更新而不必编辑各个页面。该组件采用一个文本文件(含有页面url和显示顺序),使创建按指定顺序链接起来的一些页面很容易。
       · content rotator组件采用一种配置文件来指定插入到其他页面中的html、文本或程序代码,根据配置文件指定的情况,显示内容的任何部分。
       · counters组件能够创建、递增和永久地存储各个在脚本代码中使用的整数计数器的数值。
       · logging utility组件提供对web服务器日志文件的访问,并且允许在一个asp页面内读取和更新这些数据。这是windows 2000中随iis 5.0和asp 3.0新增的特性。
       · myinfo组件为可在整个网站内访问的名称/值对的存储提供了一个存储空间,这些数据在服务器上以xml格式的文本文件存储(不同于应用程序作用域,这些数据在web网站范围之外仍然保留)。
       · page counter组件记录访问一个页面的次数,可以用于跟踪页面的点击次数。
       · permission checker组件有助于防止当一个用户试图访问没有正确的权限设置的资源时引起的脚本错误。
       · tools组件提供了一些在页面中可以采用的方法,这些方法用于检验一个文件是否存在、处理html窗体、生成一个随机整数。另外还有一些用在macintosh苹果计算机上的方法,可以检查是否存在某个服务器插件程序,检查当前用户是否为网站拥有者。
       另外一个由iis/asp提供的组件,即status组件,只能用于macintosh计算机的个人web服务器上。本书没有涉及该组件,若要详细了解该组件,可通过http://localhost/iis/htm/asp/complqt0.htm查阅asp/iis提供的iis 5.0文档。

6.2.1 使用示例页面
       本书已经提供了一系列的示例页面来说明所有这些组件的用法。
       可以从wrox web网站上下载这些实例页面,并在自己的计算机上运行。在下载的文件的chapter06子目录中会找到本章所用的程序代码。
       在运行示例页面之前,确保myinfo和counter组件的“全局”实例化代码已包含在缺省web站点的global.asa文件中。在示例文件中提供了global.asa文件中所需要的代码,可以将这些代码加到现有的global.asa文件中,不需要更换整个文件。
<!-- declare instance of the asp counters component with application-level scope
-->
<object id="objcounters" runat="server" scope="application"
progid="mswc.counters">
</object>

<!-- declare instance of the asp myinfo component with application-level scope
-->
<object id="objmyinfo" runat="server" scope="application" progid="mswc.myinfo">
</object>
示例文件的主菜单页面(default.asp)使用content linking组件创建到每一个页面示例的链接。因此,我们将首先研究这个组件,也涉及了ad rotator和counters组件的有关问题。

6.2.2 content linking组件
       content linking组件对网站是非常有用的工具,它提供了内容页面,或者包含对同一站点上其他页面的链接列表的页面。它自动把当前显示页面的url与存储在服务器里的文本文件的页面列表匹配起来并且能允许用户通过页面列表按正反顺序进行浏览。也就是说,即使访问者已经在内容页面中点击了一个链接并且正在查看列表中的某一个页面,该组件仍然会辨认出所访问的页面在列表中的位置。
       因为所有详细资料均在一个文本文件中,维护网站以及页面的链接仅仅需要编辑这个文本文件。例如可以通过在内容链接列表文件中重新排列页面的顺序,来改变它们的显示顺序。
1.  内容链接列表的文件
内容链接列表文件包括一个简单的按显示顺序排列的url列表,同时也提供了相应的描述,用于在内容页面中显示链接文本。如果需要,还可以增加对每个页面的注释,注释可以帮助识别链接,但对访问者来说注释是不可见的。
列表文件对于每个页面包含一个文本行。每一行由url、描述和注释所组成,各部分由tab字符(不是空格,否则文件将不能工作)分隔,最后有回车结束。例如:
newpages.htm        new additions to our site              we update this weekly
offers.htm            special offers for this week         we only update this monthly
register.htm           registration for new users
main.htm               the main forum and chat area      must be registered first
index.htm              back to the contents page
请注意目标url必须由一个相对的虚拟或物理的路径来说明,诸如forumenter.htm。url不能使用“http:”、“//”或者“\”作为开头,如果要创建上述这样含有绝对url的菜单,可以使用asp建立一个重新定向页面,而且在内容链接列表文件中对其进行指定,例如,建立一个名为redirect.asp的页面,包含如下代码:
<%
'redirect the request to the site specified in the query string
response.clear
response.redirect request.querystring("url")
%>
可以在内容链接列表文件中按下述方式使用redirect.asp文件:
redirect.asp?url=http://www.cyscape.com/         cyscape browserhawk web pages
redirect.asp?url=http://www.softartisans.com/     sa fileup component pages
redirect.asp?url=http://www.stonebroom.com/swindex.htm              stonebroom regex pages
2.  content linking组件的成员
content linking组件提供了八种方法,如表6-1所示。这些方法能够检索来自内容链接列表文件的条目,既能相对于当前页面检索条目,也可以使用索引号检索绝对条目。第一个条目的索引号是1。
表6-1  content linking组件的方法及说明
方 法
说 明

getlistcount(links_file)
返回文件links_file中条目的数量

getlistindex(links_file)
返回文件links_file中当前页面的索引号

getnexturl(links_file)
返回文件links_file中下个页面的url

getnextdescription(links_file)
返回文件links_file中下个页面的描述

getpreviousurl(links_file)
返回文件links_file中前一个页面的url

getpreviousdescription(links_file)
返回文件links_file中前一个页面的描述

getnthurl(links_file,n)
返回文件links_file中第n个页面的url

getnthdescription(links_file,n)
返回文件links_file中第n个页面的描述

       如果当前页面不在内容链接列表文件中,则:
       · getlistindex返回0。
       · getnexturl和getnextdescription返回列表文件中最后一个页面的url和描述。
       · getpreviousurl和getpreviousdescription返回列表文件中第一个页面的url和描述。
3.  使用content linking组件
一旦创建了自己的内容链接文件,就可以把该组件添加到页面中。这里有一个典型的示例,它遍历内容链接文件中的所有条目,并且创建一个页面列表(以超链接表示页面)。
<% ' in vbscript:
set objnextlink = server.createobject("mswc.nextlink")
%>

<ul>
<%
'get the number of entries in the menu file
intcount = objnextlink.getlistcount("contlink.txt")
'loop through the entries
for intloop = 1 to intcount %>
       <li>
       <a href="<% = objnextlink.getnthurl("contlink.txt", intloop) %>">
       <% = objnextlink.getnthdescription("contlink.txt", intloop) %>
       </a>
<%
next
%>
</ul>
这段代码首先创建了一个content linking对象。在普通的<ul>和</ul>标记之间,使用content linking对象的getlistcount方法查找在内容链接列表文件有多少条目。然后再遍历这些条目,对于每一个条目在页面中放入一个<li>标记,后面跟着一个<a>标记。href属性的值从列表文件中使用getnthurl方法检索得到,用作链接文本的描述使用getnthdescription方法得到。
注意,内容列表文件和使用它的asp页面应处在同一文件夹中。否则,应提供一个相对物理路径或一个完整的虚拟路径,如下所示:
incount = objnextlink.getlistcount("linkscontlink.txt")           'physical path
incount = objnextlink.getlistcount("/demo/contlink.txt")        'virtual path
(1)    创建一个内容页面
我们已经使用content linking组件为本章提供的示例创建了菜单页面。chapter06文件夹中的页面default.htm采用上述代码创建菜单,如图6-2所示:

       可以看到内容链接列表文件的内容显示在链接的下面,我们使用filesystemobject对象完成这一工作。
       <%
       'create an instance of a filesystemobject object
       set objfso = server.createobject("scripting.filesystemobject")

       'open the text file as a textstream object
       set objtstream = objfso.opentextfile(server.mappath("contlink.txt"), forreading)
       response.write objtstream.readall                          'read the whole file and put into page
       objtstream.close
       %>
       如果你编辑了contlink.txt文件,下次再次调用这个页面时,会看到菜单的条目发生了变化。注意文件中的最后三个条目,这三个条目使用前面介绍的redirect.asp技术,把绝对(而不是相对)的url插入到列表中。
(2)    浏览这些页面
创建一个content linking组件实例并且使用它的一个方法时,将把当前页面的url与指定的内容链接列表文件中的条目相匹配。不仅能用该组件创建一个内容列表(就像刚看到的那样),而且当在浏览器上打开其中一个页面时,可以用该组件对列表中的各个页面进行导航。
这意味着可以用超链接或按钮从这些页面中的一个移到另一个。例如,可以给页面添加next和back按钮,通过使用getnexturl和getpreviousurl方法能知道列表中的哪一个页面是前一个,哪一个页面是下一个。另一方面,能用getnthurl方法跳到列表中的任何页面,用getlistindex方法能知道当前页面在列表中的位置。
下面是一段给页面添加next和back按钮的代码,我们要做的只是把这段程序放在内容链接文件所列出的每一页中,或者用ssi的#include指令将它插入其中。
<!-- need a form to force navigator to display the buttons -->
<form action="">
<%
'we'll insert this into each page using an ssi #include statement
'create an instance of the content linking component
set objnextlink = server.createobject("mswc.nextlink")
'set the content linking list file path and name
strlistfile = "contlink.txt"
'get the index of the current page in the list
intthispage = objnextlink.getlistindex(strlistfile)
if intthispage > 1 then  'can go back
%>
  <input type=button value="< back"
     onclick="location.href='<% = objnextlink.getpreviousurl(strlistfile) %>';"
     title="go to '<% = objnextlink.getpreviousdescription(strlistfile) %>'">
   
<%
end if
%>
<input type=button value=" menu " onclick="location.href='default.asp';"
       title="return to the main 'installable components' menu">
<%
if intthispage < objnextlink.getlistcount(strlistfile) then  'can go forward
%>
   
  <input type=button value="next >"
         onclick="location.href='<%= objnextlink.getnexturl(strlistfile) %>';"
         title="go to '<% = objnextlink.getnextdescription(strlistfile) %>'">
<%
end if
%>
</form>
第一步是创建content linking组件,然后把列表文件名存入一个变量中,以便后面在创建页面里的客户端jscript代码时能够使用这个列表文件。另外这样做也便于页面的维护,因为如果想使用一个不同文件名仅需在一个地方改变就可以了。
现在让我们了解一下在链接列表中所处的位置。getlistindex方法提供当前页面的索引号,从列表中的第一页开始。如果当前页面的索引号比1大,那么可以后退,所以我们在页面中创建back按钮。如果当前页面的索引号比列表中的项数少,创建next按钮。页面中总是包括一个home按钮,以便访问者在任何时候都能轻易地返回到内容页面。
如果打开列在主菜单中的页面之一的话,将会看到使用这项技术在每个页面上创建的一系列导航按钮,创建按钮的代码在文件contlinkbuttons.inc中,可用#include指令将它插入每个页面中。图6-3所示为带有按钮的界面。

       在图6-3中有三个按钮,使用getpreviousdescription方法获得上个页面的链接文件,并把这个文本放入back按钮的title属性中,作为弹出的提示。
       <input type=button value="< back"
onclick="location.href='<% = objnextlink.getpreviousurl(strlistfile) %>';"
          title="go to '<% = objnextlink.getpreviousdescription(strlistfile) %>'">
       next按钮采用getnextdescription方法完成类似的工作。
(3)    用javascript跳转
这些导航按钮使用javascript(而不是vbscript)装载新页面,这样就能够和大多数现代浏览器兼容。例如back按钮包含下面的属性:
onlick="location.here='<% = objnextlink.getpreviousurl(strlistfile) %>'; "
当页面的html版本由asp创建时,在<%…%>标记中的表达式用其数值取代,所以发往浏览器的网页看起来如下所示:
onclick="location.herf='permissionchecker.asp'; "
为什么选择使用变量来表示内容链接列表文件的名字?其原因是在单个语句中包括一个三层的嵌套引用是非常麻烦的。
注意浏览器的缺省语言是javascript(或ie中的jscript),而不是vbscript,通过使用javascript,可以避免在onclick代码中必须提供language参数,同时对非ie浏览器提供兼容性。

6.2.3 ad rotator组件
       ad rotator组件允许浏览器在引用asp页面时每次显示不同的图像,这项技术经常用在显示广告的站点上。每次打开或重新载入页面时,asp采用“旋转调度文件”(rotator schedule file)中的信息选择一副图像,并插入网页中。然而ad rotator组件能做更复杂的工作,它可以把图像设置成超级链接而不是一副静止的图像,并能记录用户对每个广告的点击次数。
       在本章所介绍的组件中,ad rotator组件可能是最难使用的,因为它涉及几个不同的文件。在查看每个文件之前,图6-4所示的工作过程总览可能有助于了解它们之间的组合方式。

1.  旋转调度文件
ad rotator组件依赖于该文件来指定显示的广告或图像。这个文件包括每个图像文件的名字、显示的尺寸大小以及显示时间的相对百分数。该文件分为两部分,由一个仅含有一个星号(*)的行分隔。
文件格式如下:
redirect url
width width
height height
border border
*
adurl
adhomeurl
text
impressions
其中:
· url是执行重新定向的asp文件或程序的虚拟路径及名称。
· width和height定义了页面中广告条的大小(以像素为单位),缺省值为440×60。
· border规定了广告条边界的宽度(以像素为单位),缺省值为1,无边界时为0。
第一部分是可选的,设置应用于该文件中所有广告条的缺省值。这给设置所有图像的参数提供了一种方法,边界宽度可以使用ad rotator组件中的border属性来设置。如果忽略了一项或多项此类任选参数,而且没有明确设置对象属性,那么参数就使用其本身和缺省值。如果忽略所有这些参数,仍需包含“*”作为文件的第一行。
第二部分,即“*”后的部分,必须存在于该文件中,它提供了各个广告条的细节。对于每个广告条,下面四个参数要重复使用。这些参数是:
· adurl,是广告图像文件的虚拟路径和文件名。
· adhomeurl,是广告跳转到的url,连字符(-)表明该广告条没有链接。
· text,浏览器不支持图型文件时显示的文本。
· impressions,是一个整数,指明了此广告条显示的相对时间或时间比率,例如一个文件包含三个广告条,而且它们的impressions值分别设置为4、6和10,那么表明返回的页面中有20%可能出现第一个广告条,30%出现第二个广告条,50%出现第三个广告条。这没有指明广告条在浏览器中显示的实际时间。注意每一个广告条的实际出现是随机的,并被修改以达到需要的比率。
下面看一个重新定向文件的例子:
redirect adrotfiles/ad_redirect.asp
width 400
height 50
*
adrotfiles/wrox.gif
http://www.wrox.com/
better books from wrox press
3
adrotfiles/lunar.gif
http://www.going-to-the-moon.com/store.asp
acme lunar boost supplies
1
2.  ad rotator组件的成员
ad rotator组件含有一个方法和三个属性,方法如表6-2所示:
表6-2  ad rotator组件的方法及说明
方 法
说 明

getadvertisement(schedule_file)
使用指定的schedule_file中的信息创建并返回一个字符串,这个字符串含有把下一个合适的图像插入到该页面所需的html

       属性如表6-3所示:
属 性
说 明

border
整数型,是指广告条边界的宽度(以像素为单位),若未设定,则采用文件第一部分设定的值

clickable
布尔型,规定广告栏图像文件是否显示为一个超级链接,缺省值为true

targetfram
字符串型,目标框(frame)的名字。如果用户点击图像文件的话,这个框用于显示广告主的页面。如果忽略的话,页面装载到当前浏览器的目标框或窗口内,取代含有广告栏图像的页面,这个属性也能设置成一个标准的html框标识:_top、_new、_child、_self、_parent和_blank

3.  使用ad rotator组件
下面的代码说明了ad rotator组件的使用。创建了组件实例之后,设置属性参数并调用getadvertisement方法,指定调度文件的相对物理路径。由组件返回的html代码通过使用response.write方法插入到页面中。
<%  'vbscript example
quot = chr(34)
set objadrot = server.createobject("mswc.adrotator")
objadrot.border=0                   'no border
objadrot.clickable=true             'is a hyperlink
objadrot.targetframe="fraadframe"   'load into new window named fraadframe
strhtml = objadrot.getadvertisement("adrotfilesad_schedule.txt")
response.write(strhtml)             'put the html into the page
%>
getadvertisement方法的参数是相对于当前目录或web网站根目录的调度文件物理路径和文件名。在上面的代码中,此文件取名为adrotfiles,位于包含正在运行的asp页面的当前目录下的子目录中。如果这个文件存入web网站根目录下的adrotfiles子目录,应使用“adrotfilesmyadfile.txt”。
调用getadvertisement方法时,返回能插入网页中用于创建广告栏的html代码,对于上例中的旋转调度文件中的第一个广告栏,可以得到下列代码:
<a href="/adrotfiles/adredirect.asp?
       url=http://www.wrox.com/&image=/adrotfiles/adpics/wrox.gif">
<img src=http://www.163design.net/a/j/"/adrotfiles/adpics/wrox.gif"
       alt="better books from wrox press" width=440 height=60 border=0></a>
可以看到在常规的<a>标记中放置了图像文件,href属性设置为重定向文件的名称adredirect.asp,同时广告主的主页url和所用的图像添加到查询字符串中,因此当用户点击广告栏时,重定向文件将在服务器上载入并运行。
4.  重定向文件
重定向文件可以是一个asp页面、一个isapi dll或者是一个cgi应用程序,无论是哪一种,它必须能够接受和辨别广告主的主页url以及图像名参数。它检查这些值并决定下一步该做什么。例如通常会把用户重新定向到与此广告栏有关的url,这一点使用下面的vbscript代码很容易实现。
response.redirect request.querystring("url")
然而,重新定向文件提供给我们的不仅仅是这些。例如可以统计点击每个广告的用户数量,如果根据点击数收到广告费用的话,这将显得尤其有用。也可以用本章后面介绍的counters组件来完成这项工作。

'get the url of the advertiser's target page
stradvertiserurl = request.querystring("url")
if instr(stradvertiserurl, "wrox.com") then
   objcounters.increment("wrox")
   response.clear
   response.redirect stradvertiserurl
end if

if instr(stradvertiserurl, "going-to-the-moon") then
   objcounters.increment("lunar")
   response.clear
   response.write "sorry, this isn't a real site..."
end if

.. 'same for other advertisers

查询字符串包含图像文件名时,在脚本中也要考虑这一点,如果在调度文件中,同一广告主有三种不同的图像,可以对每个图像单独地跟踪访问次数。

if instr(stradvertiserurl, "wrox.com") then
'this is an advert for the wrox press site
       select case request.querystring("image")
              case "books.gif"
                     objcounters.increment("wrox_books")
              case "website.gif"
                     objcounters.increment("wrox_site")
              case else
                     objcounters.increment("wrox_other")
       end select
       response.clear
       response.redirect stradvertiserurl
end if

5.  一个ad rotator示例页面
本章提供的示例文件包括一个ad rotator组件演示程序,它能够从前面见过的asp installable components主菜单中打开。页面的上部显示的是一个由名为ad_schedule.txt的旋转调度文件定义的广告(可在本章示例目录下的ad rotfiles子目录中找到ad_shedule.txt),如图6-5所示:

使用的代码前面已经讨论过,这里在调度文件中仅增加了另外一些条目,以便更清楚地显示载入页面时的广告的变化情况。如果点击一个广告,将运行名为ad_redirect.asp的重定向文件中的代码,并且相应的广告主的页面在新的窗口里打开。完成该工作的代码和前面见到的相同。
在重定向文件中,可使用计数器(由counters组件创建)实例存储每个广告的点击次数。

if instr(stradvertiserurl, "wrox.com") then
   objcounters.increment("wrox")
   response.clear
   response.redirect stradvertiserurl
end if
…此页面的其余部分演示了counters组件的作用,下面介绍该组件。
6.2.4 counters组件
       counters组件能用于创建、存储、递增和检索每个计数器的值。不要把它和本章后面将要介绍的page counter组件混淆,counters组件能用于支持任何种类数据的统计。
       一个计数器含有一个整数值,能通过counters组件的方法进行运算。使用set方法设置计数器的指定值,用get方法检索计数器中的值,使用increment方法使计数器的值加1,使用remove方法删除一个计数器。所有的计数器的值存储在一个名为counters.txt的文本文件中,可在counters.dll组件所在的目录中找到该文件。
1.  counters组件的成员
counters组件提供了用于维护每个计数器组件中数值的四个方法,如表6-4所示:
表6-4  counters组件方法及说明
方 法
说 明

get(counter_name)
返回指定计数器的当前值,如果此计数器先前没有创建,道德创建并设置成0,其返回值为0

increment(counter_name)
增加指定计数器的当前值,如果此计数器先前没有创建,首先创建并设置为1

remove(counter_name)
删除指定的计数器

ser(counter_name,value)
把指定计数器的值设置成参数value提供的整数值,如果此计数器先前没有创建,先创建并设定为指定值

2.  使用counters组件
由于counters.txt文件仅有一个所有组件实例都能访问的拷贝。因此,应该只创建单个的counters组件实例,并且使之对web网站的所有页面都是可用的,实现这一点的常用方法是在缺省web站点根目录下的global.asa文件中创建一个应用程序范围的实例。
采用下面程序:
<!-- declare instance of the asp counters component with application-level scope
-->
<object id="objcounters" runat="server" scope="application"
progid="mswc.counters">
</object>
可以使用counters组件对需要完成的任务创建一个新的计数器。在下面的程序中,给出了有三项选择的调查问题,并对每一种选择的回答次数进行了统计,当使用者提交包含三项选择的窗体后,将调入这个页面。假设选项通过点击submit按钮的cmdyes、cmdno和cmdmaybe来选择,其对应值分别是“是”、“否”和“可能”。
<% 'in vbscript”
if request.form("cmdyes") = "yes" then objcounter.increment("response_yes")
if request.form("cmdno") = "no" then objcounter.increment("response_no")
if request.form("cmdmaybe") = "maybe" then
       objcounter.increment("response_maybe")
%>
如果这是第一次收到一个指定的响应,程序将创建一个新的计数器并自动初始化为1。
计数器在使用范围上没有限制,因为counters对象创建在文件global.asa中,这意味着在虚拟应用程序或web网站中创建的任何一个页面中都是可用的,所以这个“调查计数器”可用在应用程序的任何页面上,记住单个的counters对象能提供所需的许多独立计数器,不需要创建很多counters对象实例。
在前面的ad rotator组件页面示例中,研究了如何使用counters组件存储每个广告主的点击次数,也可以在页面中使用counters组件的get方法显示当前值。
wrox press: <b><% = objcounters.get("wrox") %></b><br>
stonebroom: <b><% = objcounters.get("stonebroom") %></b><br>
xtras: <b><% = objcounters.get("xtras") %></b><br>
componentsource: <b><% = objcounters.get("compsrc") %></b><br>
four cds: <b><% = objcounters.get("fourcds") %></b><br>
lunar: <b><% = objcounters.get("lunar") %></b><br>
每次加载页面时,都自动更新计数器的当前值。然而页面也包含有一些控件能调用counters组件的其他两个方法,即删除一个计数器(相当于将其设置为0)和将计数器设置成一个指定数值,如图6-6所示:

这些控件在一个<form>上,点击任何一个小的空白按钮时,此窗体便提交给同一个页面,方法与本章中的所有页面所用的几乎一样。下面的程序是为remove方法创建控件的html代码。
<form action="<% = request.servervariables("script_name") %>" method="post">

<input type="submit" name="cmdremove" value="   ">
  counter.remove ("
<select name="lstremove" size="1">
  <option value="wrox">wrox press</option>
  <option value="stonebroom">stonebroom</option>
  <option value="xtras">xtras</option>
  <option value="compsrc">componentsource</option>
  <option value="fourcds">four cds</option>
  <option value="lunar">lunar</option>
</select> ")<p>

</form>
当载入页面时,通过检查request.form集合查看点击的按钮,如果找到了某个按钮,将运行代码的相应部分。在点击remove按钮的情况下,相应的代码是:
       if len(request.form("cmdremove")) then
  strcountername = request.form("lstremove")              'get the counter name
  objcounters.remove strcountername
  response.write "removed counter '<b>" & strcountername & "</b>'.<p>"
end if
对于set方法,情况类似,但不仅仅需要从文本框中读取新值,而且在调用set方法之前,检查文本框中的值是否是有效值。
if len(request.form("cmdset")) then
  strcountername = request.form("lstset")              'get the counter name
  strnewvalue = request.form("txtset")                   'get the new value
  if isnumeric(strnewvalue) then                           'if it can be converted to a number
     intnewvalue = cint(strnewvalue)                    '… then convert it
     objcounters.set strcountername, intnewvalue
     response.write "set counter '<b>" & strcountername & _
                    "</b>' to <b>" & strnewvalue & "</b>.<p>"
  else
     response.write "<b>'" & strnewvalue & "</b>' is not a valid number.<p>"
  end if
end if
使用页面中的按钮调用counters对象的方法时,重新载入时会在页面顶端看到一段信息和计数器中的新值,如图6-7所示:


6.2.5 browser capabilities组件
       创建各种web网页时面临的问题之一是,不仅仅使用asp技术创建动态网页,而且能够使用html元素和其他客户端技术,像java applets、activex控件以及最近出现的html元素。需要意识到的是,一些访问者若使用了恰好不支持它们的浏览器,那么对于精心编制的网页,访问者看到的可能是文本、图像的杂乱组合,甚至更糟糕的还有相应工作的脚本程序代码。
       这里不讨论应当如何设计支持各种不同浏览器的网页(如果想了解这方面更多的内容,可以查阅alex homer编写的,wrox出版的《professional asp techniques for webmasters》一书,书号是isn 1-861001-79-7)。然而,确实要引用某个页面时,asp和iis提供铁browser capabilities服务器组件可以用来检测浏览器所支持的相关特征。
       用户请求来自服务器的页面时,浏览器传送的http报头包含了正在使用的浏览器的细节。在http-speak(它被称为用户代理字符串)中,定义了浏览器的名称、版本、操作系统及其兼容性。browser capabilities组件在自己的配置文件中查找这个字符串,并采用许多与浏览器特征等同的特性。因此,在网页运行的任何时候,browser capabilities组件能够提供支持或不支持某个特性的细节。
       在asp 3.0版本中,browser capabilities组件增加了一个新特性。在asp页面中包含metadata指令,指示组件从浏览器中取出一个cookie,并把其包含的任意值添加到当前的组件实例中作为新属性。这提供了一种方法,从浏览器收集更多的用户特定的信息,而不仅仅是通常从browscap.ini文件中得到的浏览器指定的信息。了解了现有的浏览器检测特性如何工作后,再回头介绍新的metadata技术。
1.  browscap.ini文件
browser capabilities组件使用一个基于服务器的browscap.ini文本文件,该文本文件必须和browscap.dll组件文件处于同一目录中。browscap.ini文件包含大多数关于以前和当前浏览器的信息,并且当浏览器的用户代理字符串与文件中的指定字符串都不匹配时,将使用browscap.ini文件中的缺省部分。所以添加关于浏览器的新信息或者更新现有的信息,只需编辑browscap.ini文件。
首先看一下browscap.ini文件的格式,该文件中的所有条目都是可选的。担包括缺省部分是非常重要的。如果使用的浏览器与browscap.ini文件中的任何一个都不匹配,并且没有指定缺省浏览器设置,那么所有的特性将设置成“unknown”。
下面是browscap.ini文件的格式:
; we can add comments anywhere, prefaced by a semicolon like this

; entry for a specific browser
[httpuseragentheader]
parent = browserdefinition
property1 = value1
property2 = value 2


[default browser capability settings]
defaultproperty1 = defaultvalue1
defaultproperty2 = defaultvalue2

[httpuseragentheader]行定义了特定浏览器的起始段,并且parent行指明了包含浏览器更多信息的另外一个定义。下面的各行定义了我们想通过browser capabilities组件可获得的属性以及对于该浏览器的相应值。如果浏览器没有列在所属段中,或者尽管列出了但没有列出所有的属性,将采用default部分所列出的属性和相应的值。
例如,这个文件包含以[ie5.0]开头的段,这个段包含有internet explorer 5.0的相应值,这里没有parent行,显示的(除了那些在default部分定义的)仅是我们显示定义的属性。
[ie 5.0]
browser=ie
version=5.0
majorver=5
minorver=0
frames=true
tables=true
cookies=true
backgroundsounds=true
vbscript=true
javascript=true
javaapplets=true
activexcontrols=true
win16=false
beta=false
ak=false
sk=false
aol=false
update=false
此段描述不和任何一个浏览器相匹配,因为,httpuseragentheader行仅仅是[ie 5.0]。然而,如果把[ie 5.0]作为父代,可以对浏览器添加针对ie5的定义:
[mozilla/4.0 (compatible; msie 5.*; windows 95*)]
parent=ie 5.0
version=4.0
minorver=0
platform=win95
这样我们把[ie 5.0]指定为浏览器的父代,则显式提供的属性将代替或增加给父代定义的相应的值,但这里也假定任何其他的属性值没有显式地列在其所属段中。
为了识别非常相似的浏览器版本,在httpuseragentheader行可以使用星号通配符,如:
[mozilla/4.0 (compatible; msie 5.*; windows 95*)]
将和下面的语句相匹配:
[mozilla/4.0 (compatible; msie 5.0; windows95)]
[mozilla/4.0 (compatible; msie 5.5; windows 95 aol)]

然而,只有在浏览器发送的用户代理字符串和不含“*”的httpuseragentheader不完全匹配的情况下,才采用通配符匹配。也只有当这种测试失败了,字符串才会企图和含通配符的httpuseragentheader相匹配,并且使用文件中所找到的确实匹配的第一个值。
最后,加上缺省浏览器段:
[default browser capability settings]
browser=default
version=0.0
majorver=#0
minorver=#0
frames=false
tables=true
cookies=false
backgroundsounds=false
vbscript=false
javascript=false
javaapplets=false
activexcontrols=false

这里假设一种最坏的情况,浏览器几乎什么都不支持。应在此基础上定义我们实际想要使用的值。但是,如果定义了一些缺省值为true,在一个unix终端上使用纯文本浏览器浏览页面时,可能达不到我们所希望的效果。
维护browscap.ini文件
关闭浏览器时,更新browscap.ini文件中相应值使其与浏览器的特性保持一致,增加一些旧的或我们关注的专用的值显然也是非常重要的。为了给用户提供方便,通常可从microsoft web网站上下载支持asp的一个相当全面的browscap.ini版本或其升级版本,而crscape inc公司提供的browscap.ini版本经常比microsoft web网站上的版本更新一些。
可以在http://www.cyscape.com/browscap/上找到最新的browscap.ini版本,并且订阅一份邮件列表就可自动地收到该文件的最新版本。crscape公司也制作一个与microsoft browser capabilities组件竞争的组件,称为browserhank(本章后面将介绍),新版的browscap.ini文件也可从http://www.asptracker.com上获得。
2.  使用browser capabilities组件
我们已经掌握了browscap.ini文件如何提供包含有关特定浏览器信息的可定制属性,下面介绍如何使用browser capabilities组件。相对而言,使用browser capabilities组件简单一些,下面创建组件的一个实例并说明其属性。
<% 'in vbscript:
set objbcap = server.createobject("mswc.browsertype")
blnvbscriptok = objbcap.vbscript             'save the result in a variable
if blnvbscriptok then
       response.write "this browser supports vbscript"
else
       response.write "this browser doesn't support vbscript"
end if
%>
上面代码程序检查浏览器是否支持vbscript并显示一个信息,可以想象这段代码根据浏览器给出的不同响应的网页,引导用户到不同的页面。
当然,使用browser capabilities组件的属性可做比这更复杂的工作,一个让人喜爱的技术是根据浏览器支持的属性为网站载入不同的索引网页。如果网站有一套使用帧(frame)的页面和一套不使用帧的页面,当用户第一次访问网站时,能够检查浏览器显示帧的能力,并将其重新定位到合适的索引网页上。
3.  使用browser capabilities的cookie特性
新版browser capabilities组件增加的特性之一是提供了一种方式,以获得更多的有关调用网页的特定客户的信息.
browscap.ini文件的信息只适用于特定类型的所有浏览器,所以组件仅能报告所安装的浏览器的共同特性,例如能知道浏览器是否支持cookie,但不能知道用户是否已在浏览器“选项”对话框中关闭了cookie。
同样,使用复杂的页面设计时,最好了解用户使用的连接类型,以便能选择大小适当的图像文件传送给他们,例如用户通过局域网(而不是调制解调器)连接,则允许我们提供更加丰富的环境。如果能知道用户采用的屏幕分辨率、浏览器所用的语言、操作系统和处理器类型等参数,对于我们的设计是有帮助的。
ie 5通过使用缺省行为提供这种信息,这是客户端网页的一个元素。ie 5中的行为是新增加的,其他的浏览器不支持,这是一种对网页中的元素添加特殊功能的方法,通过style属性(或css风格表项)和元素联系起来。特别是,ie 5提供的clientcaps行为能用于提供有关客户机和浏览器设置以及当前选项的信息。
通过创建一种元素和与之相连的clientcaps行为,能通过该元素查询到有关客户的信息。下列页面来自我们提供的示例文件(browscap_cookie.htm)正是这样做的。它首先定义了应用于<ie:clientcaps>类型的所有元素的包含clientcaps行为的风格。这是xml语法,在<html>标记的xlmns属生中使用为当前网页定义的名称空间。
然而,页面browscap_cookie.htm从应用clientcaps行为的元素得到一系列值,并且建立一个包含这些值的cookie,最后,把这个cookie分配给文档的cookie属性,以便有对这个特定服务器目录的页面请求时,将它传送给服务器。
<html xmlns:ie>
<head>
<style>
ie:clientcaps {behavior:url(#default#clientcaps)}
</style>
</head>
<body onload="createcookie();">
<ie:clientcaps id="objccaps" />

<script language="javascript">

function stopallerrors() {
  return true; // prevent display of any errors
}

function createcookie() {
  window.onerror = stopallerrors;
  var strcookie = new string();
  strcookie = 'width=' + objccaps.width
            + '&height=' + objccaps.height
            + '&availwidth=' + objccaps.availwidth
            + '&availheight=' + objccaps.availheight
            + '&bufferdepth=' + objccaps.bufferdepth
            + '&colordepth=' + objccaps.colordepth
            + '&javaenabled=' + objccaps.javaenabled
            + '&cookieenabled=' + objccaps.cookieenabled
            + '&connectiontype=' + objccaps.connectiontype
            + '&platform=' + objccaps.platform
            + '&cpuclass=' + objccaps.cpuclass
            + '&systemlanguage=' + objccaps.systemlanguage
            + '&userlanguage=' + objccaps.userlanguage;
  document.cookie = 'browscap=' + strcookie;
}
</script>

</body>
</html>
为了使用这个cookie,只需把特定的metadata指令插入到asp页面中。如下所示:
<!-- metadata type="cookie" name="browscap"
                     src="browsercapabilities/browscap_cookie.htm"-->
现在,运行这个asp网页时,会自动把页面browscap_cookie.htm发送给客户机,客户机便运行这个行为特性,然后返回cookie,随后browser capabilities组件把cookie的内容添加到组件实例的可用属性的列表中,查询方法与查询browscap.ini文件创建的属性所用的方法相同。
width: <b><% = objbcap.width %></b><br>
height: <b><% = objbcap.height %></b><br>

browser capabilities示例网页显示两类系列数值,一类是从由browscap.ini文件决定的属性中收集的数据,另一类来自客户端cookie页面。当然,不限于仅仅收集来自客户端页面中的clientcaps行为的值,使用动态html技术可以查询浏览器的任何属性或者是像navigator.appname这样的传统对象属性。browser capabilities组件示例页面如图6-8所示: