前面已经提到了很多vb开发组件的例子。
SP编程人员总是要使用到组件---其实就是以下5个ASP内建对象:Response, Request, Session, Application 和 Server,它们存在与ASP.DLL组件文件中,是WEB动态应用程序开发的基础。利用它们,花费很少的工作量就能完成一定的任务。
编写脚本可以很完美地操作这些组件对象,从而建立定制的WEB站点。但是,单单利用这些基本组件和脚本,还不能完成所有想做的事情,因此,就要考虑使用其他的组件。
许多其他组件都非常有用,比如ADO组件对于数据库的存取、运行时间脚本组件对于文件系统的存取。这些组件的共同一点就是:使用它们可以存取的对象,是用简单的代码所不能做到的。
然后,如果再找不到一个能满足任务的组件,就要考虑编写了。这篇文章就将讨论在Visual Basic中实现编写组件的方法。
用Visual Basic编写第一个ASP组件
这里要编写的组件的功能是:简单地给每个访问者一个唯一的ID号,以便日后调用。程序将检查浏览器页面请求,获取一个特殊的Cookie:VID(访问者标识符Visitor IDentifier);如果找到这个cookie值,就设置它的到期时间为从此3个月后;如果没有找到,组件就创建一个唯一的标识符,并将之存储为cookie,设置它的到期时间为从此3个月。
产生唯一的号码
创建GUID(唯一保证识别号)的代码可以从微软知识库中找到。如果机器中安装了MSDN,那么其详细资料位于:Knowledge Base / visual Basic for Windows / HOWTO: Use API to Generate a GUID with VB。
下面将详细讨论创建GUID的代码。这里将要制作的组件包含一个叫做GetGUID的方法,它返回代表一个GUID的16进制字符串。
在ASP页面中使用组件
要实现组件要完成的任务“设置Cookie和到期时间”,需要在页面主体(Body)送到浏览器之前,在HTTP头部完成GUID的计算。执行下面的代码将足够为浏览器设置一个永久的GUID。
< %@ LANGUAGE="VBSCRIPT" % >
< %
Dim oCookieSetter
Set oCookieSetter = Server.CreateObject ("ASPToday.VisitorID")
% >
$#@60; HTML $#@62;
...
创建这个独立组件的简单对象,足够可以完成要求的任务。但是在研究它之前,需要提到一些你可能注意到的事情:这里的代码使用了ASP服务对象的CreateObject方法,而不? Script中的相关函数:
< %@ LANGUAGE="VBSCRIPT" % >
< %
Dim oCookieSetter
下面的代码将不会生效 !!!!
Set oCookieSetter = CreateObject ("ASPToday.VisitorID")
% >
$#@60; HTML $#@62;
....
这样做,就保证了Server.CreateObject方法不仅创建了一个组件的实例,而且将检查组件的一对方法:OnStartPage()和 OnEndPage(),它们将在适当的时候被执行。这是创建ASP组件、访问ASP内在对象的关键。
Visual Basic工程
创建组件的步骤是:启动Visual Basic,在对话框提示时,选择要创建的工程类型,这里选择ActiveX DLL:
设置工程的属性
创建工程的名字为Project1,它包含一个单独的类模块叫做class1。这些就足够了。点击菜单“Project/Project1 Properties”,在出现的如下所示画面中设置工程的属性: 
b>设置工程的引用
完成了工程属性的选择,下一步就是设置组件运行的ASP环境。通过引用对话框实现这一步。选择菜单“Project / References”,出现一个对话框,选择组件需要的库,在这里选择“Microsoft Active Server Pages Object Library”。
在General/Tab页面上有一对需要注意的信息。首先,工程名Project Name已经改变为ASPToday,这将形成调用名字的第一个部分,这个调用的名字就是被ASP页面使用的CreateObject的名字。这里还选择了Unattended Execution选项,从而禁止了图形界面的交互(比如错误信息对话框),这么做,有可能导致IIS错误。
在Make页面唯一发生重要变化的是设置Auto Increment选项,这样做,当程序编译后,组件的版本号就会提升。调试程序时,知道组件的版本号是非常有用的,特别是当拥有一个source safe系统时,不过这是另外的话题。
编译(Compile)页面是选择让编译器如何创建组件的地方。在这里选择Optimize For Small Code,因为我要让Web服务器得到它能得到的最多内存。这个页面真正重要的选项是DLL基础地址,这和计算机调入组件相关的代码库的方式有关。做为一个32位的系统,会留下2兆字节的内存装入代码。你要设置的基础地址必须是建立在64K基础上,用英语方式表达出来就是需要设置类似 &Hxxxx0000 的数值,xxxx表示从1100到7FFF的16进制数字。
你也许要问,这是为什么呢?原因是系统在运行时间装入代码库的方式。如果用许多不同的程序库一直要装入同样的内存地址,系统就必须浪费时间和资源挑拣出哪些位于哪儿。如果编写组件时(这些组件将会一起使用)设置成不同的基础地址,那么在运行时就不会导致性能阻塞。
在Component页面,初始的版本兼容性默认是Project compatibility,如果不编译成第一个版本,这将会是不错的。当编译时,为了有利于注册表,就应该改变为Binary Compatibility,如上图所示。请查阅在线帮助得到关于这个复杂项目的详细资料。
设置工程的引用
完成了工程属性的选择,下一步就是设置组件运行的ASP环境。通过引用对话框实现这一步。选择菜单“Project / References”,出现一个对话框,选择组件需要的库,在这里选择“Microsoft Active Server Pages Object Library”。
通过上述引用,在程序中就可以访问ScriptingContext对象,从而能够使用在ASP页面中的5个对象:Request, Response, Session, Application 和 Server。
如果在列表中找不到“Microsoft Active Server Pages Object Library”,点击“Browse”按钮定位寻找。ASP库引用实际上就是一个后缀为.tlb的文件,默认的路径应该位于:\Program Files\Microsoft Visual Studio\ Common IDE\IDE98\ASP.TLB。
设置工程的引用
完成了工程属性的选择,下一步就是设置组件运行的ASP环境。通过引用对话框实现这一步。选择菜单“Project / References”,出现一个对话框,选择组件需要的库,在这里选择“Microsoft Active Server Pages Object Library”。
通过上述引用,在程序中就可以访问ScriptingContext对象,从而能够使用在ASP页面中的5个对象:Request, Response, Session, Application 和 Server。
如果在列表中找不到“Microsoft Active Server Pages Object Library”,点击“Browse”按钮定位寻找。ASP库引用实际上就是一个后缀为.tlb的文件,默认的路径应该位于:\Program Files\Microsoft Visual Studio\ Common IDE\IDE98\ASP.TLB。
在组件中命名对象
在开始编程前,工程的唯一类模块class1,实在应该含有一个更有意义的名字。在工程浏览(Project Explorer)窗口中选择类项目:
(如果在编程环境中看不到这个窗口,按“Ctrl+R”组合键调出它)在上面的窗口中就可以修改类的名字属性,接着出现属性对话框。
修改名字为VisitorID。如果看不到这个对话框,按F4显示它。
编制代码
到此为止,已经为组件设置了足够的属性,建立好了在ASP页面中调用组件实例的基础。但是,还需要一个接口方法。下面的图表显示了将要建立的接口(用长方形描述对象的方法,用园描述属性)。
在Visual Basic中,打开类VisitorID的代码编辑器(在工程浏览器中双击它的图标)。
首先建立类的一些变量声明:
Private mstrError As StringPrivate mobjSC As ScriptingContextPrivate Const VISITOR_COOKIE = "VID"Private Const S_OK = 0 return value from CoCreateGuidAPI Declarations
Private Type GUIDData1 As LongData2 As IntegerData3 As IntegerData4(7) As ByteEnd Type
Private Declare Function Co ateGuid Lib "OLE32.DLL" (pGuid As GUID) As Long
上面的代码有三个注意事项:
- OptionExplicit表示必须在模块中首先声明变量
- 定义了一个数据结构和一个扩展API函数,并且是私用的(Private)。GetGUID方法将使用它们。
- 定义了一个ScriptingContext类型的对象变量,ASP处理器根据这个应用传递给组件。
ASP接口
因为编制的组件是在ASP页面中使用的,所以需要一对方法,从而可以被ASP处理器调用,这对方法是:OnStartPage 和 OnEndPage。首先看看OnStart:
Public Function OnStartPage(ByVal sc As ScriptingContext)Dim strID As StringDim dtmExpires As Date
IMPORTANTNEVER Leave a public method without an error handler.An error would bring down the IIS server Instanceor application.
On Error Goto er_FailStore the context of the HTTP requestSet mobjSC = scThis component doesnt actually need to store thecontext past the end of this routine,but we store it for future development and use.Check whether the VID cookie is present in the Request object
strID = Trim(sc.Request.Cookies.Item(VISITOR_COOKIE))if no cookie foundIf strID = vbNullString Thensc.Response.Cookies.Item(VISITOR_COOKIE) = GetGUIDEnd IfNow set the lifetime of the cookiedtmExpires = DateAdd("m", 3, Now)sc.Response.Cookies.Item(VISITOR_COOKIE).Expires = Day(dtmExpires) & _" " & MonthName(Month(dtmExpires)) & " " & Year(dtmExpires)Exit FunctionTHE ERROR HANDLERer_Fail:just add some text to the error info propertymstrError = mstrError & Err.Description & ":" & Err.Description & vbCrLfI do not expect any critical errorsso continue execution on next lineResume NextEnd Function
以上方法代码中包含3个部分:
1、ASP处理器检查Scripting Context,并存储引用到事先声明的变量中。
2、检查Request对象的Cookies集合的VID项目,如果没有,就从GetGUID方法中获得一个值。
3、Cookie的使用到期期限设置为此后3个月。
Public Function OnEndPage()
Release Scripting context
Set mobjSC = Nothing
End Function
OnEndPage方法是放置清理代码的地方。比如说,释放关于ScriptingContext的引用。实际上,并不是必须要保存这个引用,但是为了以后的扩充,还是保存为好。
函数GetGUID
这个函数的代码可以从MSDN知识库中得到,这里做了一些修改:
Public Function GetGUID() As StringDim lResult As LongDim lguid As GUIDDim MyguidString As StringDim MyGuidString1 As StringDim MyGuidString2 As StringDim MyGuidString3 As StringDim DataLen As IntegerDim StringLen As IntegerDim i As IntegerOn Error GoTo error_olemsglResult = CoCreateGuid(lguid)If lResult = S_OK ThenMyGuidString1 = Hex$(lguid.Data1)StringLen = Len(MyGuidString1)DataLen = Len(lguid.Data1)MyGuidString1 = LeadingZeros(2 * DataLen, StringLen) _& MyGuidString1 First 4 bytes (8 hex digits)MyGuidString2 = Hex$(lguid.Data2)StringLen = Len(MyGuidString2)DataLen = Len(lguid.Data2)MyGuidString2 = LeadingZeros(2 * DataLen, StringLen) _& Trim$(MyGuidString2) Next 2 bytes (4 hex digits)MyGuidString3 = Hex$(lguid.Data3)StringLen = Len(MyGuidString3)DataLen = Len(lguid.Data3)MyGuidString3 = LeadingZeros(2 * DataLen, StringLen) _& Trim$(MyGuidString3) Next 2 bytes (4 hex digits)GetGUID = _MyGuidString1 & MyGuidString2 & MyGuidString3For i = 0 To 7MyguidString = MyguidString & _Format$(Hex$(lguid.Data4(i%)), "00")Next iMyGuidString contains last 8 bytes of Guid (16 hex digits)GetGUID = GetGUID & MyguidStringElseGetGUID = "00000000" return zeros if function unsuccessfulEnd IfExit Functionerror_olemsg:mstrError = "Error " & Str(Err) & ": " & Error$(Err)GetGUID = "00000000"Exit FunctionEnd Function
这个方法本质上是调用API函数,并且将它提供的数据格式化为一个16进制字符串。这里添加了出错处理代码。
MSDN中的代码在出错时显示一个信息框,但这对于ASP组件却是不行的,所以这里的代码设置了一个内部字符串变量,作为ErrorInfo属性值。通常而言,我们希望这个字符串是空的,这表示组件没有错误。这个方法也调用了LeadingZeros函数来格式化数据。
Private Function LeadingZeros(ExpectedLen As Integer, ActualLen As Integer) As StringLeadingZeros = String$(ExpectedLen - ActualLen, "0")End Function
最后,加入ErrorInfo属性:
Public Property Get ErrorInfo() As StringErrorInfo = mstrErrorEnd Property
编译组件和分发组件
为了使用新组件,必须将之生成DLL文件。选择菜单“File/make ASPToday.dll ...”,接着选择生成组件的路径。
组件创建完成后,就要建立一个组件分发软件包。除了Visual Studio自带的,有许多第3方工具可以做这件事情,它们都提供了强大的向导来帮助建立一个安装程序,从而在Web服务器上安装组件。
总结
现在你了解了如何建立一个简单的组件,你可以在对象中加入许多通用的代码。使用这种方法可以很好地实现ASP页面与ADO代码的分离。使用组件编程可以使程序变得简单易懂,因为,它将你的精力集中在应用程序的重要方面上,而将一些重复琐碎的处理细节放到了“黑箱”中,这个“黑箱”就是你建立的组件。
