为 IIS-MTS 开发一个 Visual Basic 组件(COM+ 技术文章)

为 IIS-MTS 开发一个 Visual Basic 组件(COM+ 技术文章)

发布日期: 5/20/2004 | 更新日期: 5/20/2004

Troy Cambra
支持工程师
Microsoft 公司

2001 年 9 月更新

摘要:本文讲述如何利用 IIS 和 MTS 的新功能构建组件,并提供了有关组件构建、性能、进程独立和调试等技巧的丰富列表。(19 页打印页)

*
本页内容
简介 简介
为什么要编写组件? 为什么要编写组件?
为什么使用 Microsoft Transaction Server? 为什么使用 Microsoft Transaction Server?
为什么要使用 Visual Basic? 为什么要使用 Visual Basic?
使用 MTS 对象 使用 MTS 对象
使用 ASP 内部对象 使用 ASP 内部对象
性能和进程独立的技巧 性能和进程独立的技巧
构建 MTS 组件的技巧 构建 MTS 组件的技巧
调试技巧 调试技巧

简介

Microsoft Internet 信息服务器 (IIS) 4.0 与 Microsoft Transaction Server (MTS) 2.0 的集成提供了一个强大的服务器环境。这种集成可以提供进程独立、事务性 Web 页支持,以及将组件构建到 IIS 中的一个丰富框架。本文讲述如何利用 IIS 和 MTS 的新功能构建组件,并提供了有关组件构建、性能和进程独立、调试等方面技巧的丰富列表。

本文假设读者已充分具备 Internet Information Server、Active Server Pages (ASP)、Microsoft Transaction Server (MTS)、Microsoft Visual Basic 6.0 以及组件对象模型 (COM)等方面的丰富知识。您可以从 Microsoft Windows NT 的可选补丁包中安装 IIS 4.0 和 MTS 2.0。补丁包可以从 http://www.microsoft.com/windows/downloads/default.asp 下载。

目前,Internet 信息服务 5.0 版可从 Microsoft Windows 2000 中获得。Microsoft Transaction Server 已经与 COM 技术合并成为 COM+ 服务,也可以通过 Microsoft Windows 2000 获得。

为什么要编写组件?

通过 ASP,完全可以仅使用 IIS 提供的功能来构建丰富的应用程序。您无需写组件,就可以访问服务器上下文,执行事务,访问数据库以及执行其他操作。于是你也许会问,那为什么还要编写组件呢?有三个最重要的原因:

性能和可伸缩性。执行本地代码比解释脚本更快速而且通常占用的内存更少。

业务逻辑封装。这样做可以创建更好的代码结构,也可以改进代码的调试、发布以及升级。此外,您也可以在应用程序中或应用程序之间重用这些组件。

数据与用户界面 (UI) 的分离。利用这些组件,很容易为应用程序添加一个新的用户界面,而无需涉及业务逻辑和数据。这对于变化迅速的基于 Web 的应用程序来说极为重要。

要了解关于组件的更多信息,请参阅Agility in Server Components

为什么使用 Microsoft Transaction Server?

如果要在网站中使用分布式事务,那么 MTS是显而易见的选择。然而,即使不使用事务或数据库,你也会发现 MTS 是一个非常有用的运行组件的环境。MTS 提供了对象代理、运行时服务以及事务监视。 如果组件需要以下功能,请考虑 MTS:

事务性支持

容错

进程隔离

可管理的组件与接口安全

ASP 内部对象的访问

线程管理

审计

资源池

为什么要使用 Visual Basic?

任何能够创建单元线程式进程内 COM 组件的编程语言都适于开发 MTS 组件。编程语言的选择应该主要建立在您对语言的熟悉程度以及它是否适合该任务的基础上。对一门编程语言的熟悉程度是最重要的因素。知道如何正确的使用一门编程语言并且最大限度地发挥它的效率和作用在很大程度上可以决定一个项目的成败。当然,也需要考虑编程语言是否适于任务。例如,如果运行速度极为重要的话,使用像 C++ 这样的“低级”语言是较好的选择。

Visual Basic 是大多数应用程序的实际编程工具。它是一门成熟、稳定、已得到实际检验的编程语言。并且它也是一个完备的快速应用程序开发 (RAD) 工具,具有足够的灵活性来调用底层 API,使开发人员可以调整程序性能或提供高级功能。

使用 MTS 对象

ActiveX DLL 项目中的任何类都可能潜在地成为 MTS 组件。可是,要充分利用 MTS 的功能,使用 MTS 程序员接口是必要的。要实现这一点,首先要引用 Microsoft Transaction Server 类型库。这样可以启用对 MTS 对象的访问,最重要的 MTS 对象是 ObjectContext? . ObjectContext 提供对对象 MTS 上下文的访问,MTS 上下文则提供核心 MTS 功能。

在 MTS 中,工作的逻辑线程称为活动。一个活动可以跨越多个对象和对任意对象的多个方法调用。一个活动的作用范围跨越了从基础客户端的第一个调用到根对象调用 ObjectContext.SetComplete,以及退出此方法或基础客户端释放根对象。虽然可能会有活动跨越多个对象或一个对象的多个方法调用,但是如果可能的话,最好将活动限制在每个对象调用一个方法里。如果这样做的话,您可以获得方法里的上下文并在退出之前释放它。代码如下所示:

Public Sub SomeMethod()
Dim objCtx as ObjectContext
Set objCtx = GetObjectContext
If objCtx Is Nothing Then _
Err.Raise 91 'error if failed
'Perform work.
Set objCtx = Nothing
End Sub

如果活动跨越了好几个方法调用,而且所有调用都需要访问对象的上下文,那么把对象的上下文存储到类成员变量里通常是一个好想法。在 Initiate 事件时获得对象的上下文,在 Terminate 事件时释放它,这并不是很好的方式。类的构造函数和析构函数必须要考虑事件,所以不能假设一定能够获得上下文。并非只是 Visual Basic 才有这种情况,对于所有其他编程语言来说,要获得更好的错误处理和可靠性,也应该因为一致性而遵循同样的问题。

当活动跨越了好几个方法调用时,获得和释放上下文最好的方法是使用 ObjectControl 接口方法。 ObjectControl 为上下文处理提供了一种坚实的机制,也允许组件在未来版本提供对象池时利用它。

ObjectControl 接口方法在类模块中处理上下文的代码如下所示:

Option Explicit
'Private class member variables
Private m_objCtx As ObjectContext
'Public class functions
'Implementation of ObjectControl interface
Implements ObjectControl
Private Sub ObjectControl_Activate()
Set m_objCtx = GetObjectContext
If m_objCtx Is Nothing Then _
Err.Raise 91 'error if failed
End Sub
Private Function ObjectControl_CanBePooled() As Boolean
ObjectControl_CanBePooled = False  'don't pool for now
End Function
Private Sub ObjectControl_Deactivate()
Set m_objCtx = Nothing 'release
End Sub
'Actual public class functions
'TBD

一旦获得上下文,您就可以用它来控制事务结果和对象回收,也可以用它来查询上下文属性并执行各种函数。以下函数显示了上下文属性和方法的典型使用:

  Public Function BasicFunction(ByVal blnAudit As Boolean) As Variant
      'sample MTS function
      Dim strAuditString As String
      Dim strErrString As String
      'This function will optionally log auditing information
      On Error GoTo ErrHand
      If blnAudit Then
          strAuditString = "Method:BasicFunction " & vbCrLf & _
              "Thread ID:0x" & Hex(App.ThreadID) & vbCrLf & _
              "Transactional:" & m_objCtx.IsInTransaction & vbCrLf & _
              "DirectCaller:" & m_objCtx.Security.GetDirectCallerName & vbCrLf & _
              "OriginalCaller:" & m_objCtx.Security.GetOriginalCallerName
          Call App.LogEvent(strAuditString, vbLogEventTypeInformation)
      End If
      'Perform the actual work
      'Actual work TBD
      'Finish up
      BasicFunction = "Something Wonderful Happened"
      'Commit the transaction
      m_objCtx.SetComplete
      Exit Function
  ErrHand:
      'log the actual error
      strErrString = "Error Code:0x" & Hex(Err.Number) & vbCrLf & _
          "Error Description:" & Err.Description & vbCrLf & _
          "Error Source:" & Err.Source
      On Error Resume Next
      Call App.LogEvent(strErrString, vbLogEventTypeError)
      'Abort the transaction - if one
      m_objCtx.SetAbort
      'Raise a friendly error to the caller.Minimizing the number of
      'errors returned to the client makes programming at that level
      'easier.For example, you typically have two types of errors
      'recoverable and non recoverable.You could simply send back
      'one or the other so the caller can easily make a decision
      'about how to handle it.
      Call Err.Raise(vbObjectError + 1001, _
          "Basic Component", _
          "Basic Error.Please contact the system administrator")
  End Function

使用 ASP 内部对象

ASP 内部对象可通过对象上下文在 MTS 对象中获得。利用 MTS 对象中的 ASP 内部对象十分简单,而且非常有用。例如,如果有一个 ASP 页面使用响应对象来构建复杂的 HTML 页面,可以将代码封装到组件里,这样可以执行得更快,也更容易调试。电子商务网站可以用这种方法构建一个页面,它能够报告正在执行的复杂事务的进度。下面是一个组件和调用它的一个示例 ASP 脚本中的示例函数:

组件

  Public Function ASPVarUse() As Variant
      'sample mts function
      Dim strErrString As String
      Dim objApplication As Object
      Dim objResponse As Object
      Dim objRequest As Object
      Dim objServer As Object
      Dim objSession As Object
      Dim objItem As Object
      On Error GoTo ErrHand
      'Get the IIS intrinsic objects
      If m_objCtx.Count < 5 Then _
          Call Err.Raise(vbObjectError + 1002, "Basic Function", _
          "This object is meant to be called by ASP pages only")
      Set objApplication = m_objCtx.Item("Application")
      Set objResponse = m_objCtx.Item("Response")
      Set objRequest = m_objCtx.Item("Request")
      Set objServer = m_objCtx.Item("Server")
      Set objSession = m_objCtx.Item("Session")
      'Access the ASP objects
      objResponse.Write " Outputting from the MTS component "
      Call objServer.HTMLEncode("The paragraph tag:")
      objApplication("AppTest") = "Application Test"
      objSession("SessionTest") = "Session Test"
      For Each objItem In objRequest.QueryString("RequestTest")
          objResponse.Write objItem & ""
      Next
      ASPVarUse = "Successful Test"
      'Commit the transaction
      m_objCtx.SetComplete
      Exit Function
  ErrHand:
      'log the actual error
      strErrString = "Error Code:0x" & Hex(Err.Number) & vbCrLf & _
          "Error Description:" & Err.Description & vbCrLf & _
          "Error Source:" & Err.Source
      On Error Resume Next
      Call App.LogEvent(strErrString, vbLogEventTypeError)
      'Abort the transaction - if one
      m_objCtx.SetAbort
      On Error GoTo 0
  'Raise a friendly error to the caller.
      Call Err.Raise(vbObjectError + 1001, _
          "Basic Component", _
          "Basic Error.Please contact the system administrator, error:" & strErrString)
  End Function

ASP 脚本

  <%
  Dim objTest

  On Error Resume Next
  'Create the MTS object
  Set objTest = Server.CreateObject("PMTSIISVB.IMTSIISVB")
  If Err.Number <> 0 Then
      Response.Clear
      Response.Write "<p> " & Err.Description & " </p>"
      Response.End
  End If

  Response.Write "<p> Starting Test </p>"
  Response.Write "<p> ASPVarUse Return: " & objTest.ASPVarUse() & " </p>"
  If Err.Number <> 0 Then
      Response.Clear
      Response.Write "<p> " & Err.Description & " </p>"
      Response.End
  End If
  Response.Write "<p> Session Variable = " & Session("SessionTest") & " </p>"
  Response.Write "<p> Application Variable = " & Application("AppTest") & " </p>"
  Response.Write "<p> Ending Test </p>"
  %>

性能和进程独立的技巧

在容错、编程的容易性以及程序性能之间保持平衡是很棘手的事情。为了细微调整程序的性能,需要做许多事情。我把为了改善性能,该做和不该做的一些比较常见的事情整理到一张表中。有关 IIS 和 ASP 性能调整的更详细的讨论,请参见:Internet 信息服务器资源包

尽可能地使用池进程的 ASP 页面以及组件。如果 IIS 服务器是一个单使用的服务器(您的应用程序是唯一的一个),而且您确信 ASP 页面以及 MTS 组件的健壮性,那么它们都在 IIS 进程中运行是可以接受的。注意:如果运行在 IIS 进程中,ASP 页面或组件的问题就可能造成整个服务器的瘫痪。在 5.0 以及更高版本的 IIS 中,提供了一种被称为进程外入池的进程独立新方法。标记为池的应用程序并不共享 IIS 进程中的空间,但它们也不在自己的进程空间中。所有池应用程序共享一个进程,这样不仅保护了 IIS 进程,而且也改善了程序性能。

全面地分析整个服务器是很重要的。您也许会认为在每个应用程序中、或者在每个虚拟 Web 站点进程内、或者在池进程中运行每个 ASP 页面会比在进程外运行这些页面获得更好的性能。其实并不尽然。严格地说,性能方程中有几千个变量。确保最优性能的唯一办法是在应用程序开发周期里计划性能测试。例如,我曾经有一个大型网站,确实通过将一些应用程序移到进程之外获得了实质的性能改善。

如果应用程序和 IIS 服务器之间的进程独立特别重要,那么可以在一个独立的进程中运行 IIS 应用程序,但是要使用 MTS 组件的库程序包。这通常是一个很好的折衷。组件中出现的问题可能会造成应用程序的崩溃,但即使它们处于两个不同的进程,这样的问题也会以某种形式传回到 ASP。此外,这样的配置总是优于在 IIS 进程中运行 ASP 以及在服务器进程中运行 MTS 组件。

监视这些对象的引用。传递对象的指针也许会使编程更容易,但这会牺牲性能。这对于网络链接来说尤其如此,但是跨进程引用同样也会使性能受到影响。记录集是人们经常希望传递的对象。如果需要传递记录集,尤其是传递给客户端,可以使用客户批量记录集,它是 ActiveX 数据对象 (ADO) 和远程数据服务 (RDS) 的一部分。这个不连接的记录集可以根据值来封送,也可以通过 HTTP 来封送。

监视属性 Get Set 调用。用一个方法调用得到一组相关的属性通常比单独的属性 Get 和 Set 调用更有效。每次调用都需要一次往返行程,所以使方法调用和往返行程的次数最少,就可以使性能最优。换句话说,对象包含少量含较多参数的方法通常比对象包含很多属性和含较少参数的方法更有效。

避免委托。 Visual Basic 的 Implements 关键字使得程序员可以委托调用以实现简单形式的继承。这有利于代码重用,但要注意不要滥用它。委托可能会快速降低程序的性能,特别是在像 MTS 这样的无状态的环境中,对象会不断地被创建和释放。

避免在事务性组件中进行运行时目录查询。由于系统表通常很小,运行时查询就可能造成严重的数据库阻塞。这种情况可能明显也可能不明显。例如,要避免构建访问系统表的 SQL 语句是很容易的,但是要了解数据库 API 或对象中的某个标记何时产生方法去访问系统表是困难的。您必须在部署应用程序之前检查 ODBC、数据库日志和这一行为标志的跟踪记录。

留心共享数据。共享属性访问管理器、会话对象以及应用程序对象都有共享数据。但是,单元线程的对象绝对不可存储到它们中,在存储其他数据时也要注意不可滥用它们。接口封送和线程同步(分别)都能够影响性能。

避免访问未调整的 COM 服务器。例如,我曾经见过 MTS 应用程序在存储数据之前调用 Microsoft Word 对它进行格式化,等等。Word 和其他这样未调整的 COM 服务器并不是按照最优的思路开发的,所以通常其性能决不是最优的。

避免存储状态。在几种情况下存储状态是有益的,但是在大多数情况下,存储状态会损害可伸缩性并导致出现其他问题。

不要从 ASP 页面直接向机器外调用。参见知识库文章 Q159311,可从 http://www.microsoft.com/support/ 下载,文章讨论了使用 IIS 机器上的中间 MTS 包,并继而调用远程服务器。这样做的实际原因是出于安全性考虑,第一次听说这种做法时,我曾想:“这是多么可怕的性能恶梦啊”。可是,在我对它进行了仔细研究并试过几个例子之后,我意识到可以用它来改善性能。

ASP 页面将使用组件的 IDispatch 接口。这导致每个方法调用都被调用两次。如果能够在早期绑定中间组件,就可以限制网络调用为每个方法调用一次。而且,您可以设计中间组件容纳引用、缓存数据等等。这样做可以使通过网络存取数据的频率和数量最小。

在事务性组件中使事务持续时间最短。MTS 为第一个事务性组件实例化的对象启动一个 Microsoft 分布式事务协调器 (DTC) 事务。然后该事务就可以贯穿整个活动。即使这个事务实例化,资源管理器事务也要等到有程序试图第一次访问它时才会启动。因此,应该尽可能迟地启动这个事务,尽可能长时间地延迟实际的资源管理器访问,并尽可能快地结束这个事务。

构建 MTS 组件的技巧

下面是在 IIS 里使用的构建 MTS 组件的一个建议列表。这不是一组规则,而是灵活的指导原则。

在每次方法调用里进行 SetComplete/SetAbort 操作。无状态是进入 MTS 的方式。但并不是说在一个活动里应该有多个对象。它只是意味着您应当只对事务中任何给定的对象进行调用。如果使用次数增加,跨越多个方法的活动可能会进入到一个死锁状态。 此外,这样做可以为了性能简化执行路径,也有利于消除可能的故障点(特别是对于远程组件)。

经常检查 Retain in Memory Unattended Execution。没有这些标志,VB 运行时就会不断地卸载和重载。这样不利于线程安全。肯定会进入挂起和崩溃状态。

在启动前进行示例测试来比较方法、组件和工具。 这样可以在早期给您性能和问题的概念。例如,使用 ODBC API 可以产生很快的代码,但是增加开发成本是否值得?或者用一点额外的硬件,仔细开发一些 ADO 代码是否更有意义? MTS 性能小组正着手发布一些性能数据,但是应用程序的简单原型也可以提供有价值的信息。

考虑未来。应用程序需要伸缩到什么程度?需要变得更分布吗?需要位置透明吗?这些类型的问题都会影响开发。例如,如果应用程序不需要特别的伸缩性并总是在进程内运行,传递对象引用和执行很多属性 GetSet 也许并不是问题。如果应用程序需要变更,性能和可靠性可能都会由于这样的设计而受损害。

以不少于计划在相似的硬件上部署和运行程序的用户数(模拟)进行测试。在整个开发周期中都以这种方式进行测试。应用程序经常以单用户模式或者也许有几个客户来进行开发和测试。然后应用程序在重负载情况下测试 — 或者更糟糕的是大批量地发布给用户,最后以失败告终。

使用一致和通用的错误处理机制。错误处理机制通常是一种亡羊补牢之举。这在桌面应用程序中通常不会产生问题,但是在关键任务的多层分布式应用程序中,未仔细筹划和测试的错误处理会导致严重问题。在以后的文章里,会涉及到错误处理技术。

要小心第三方控件和对象库。虽然它们也许能提供一些较酷的功能或核心逻辑,但很多控件都还没有对 MTS 进行测试,另一些控件也从未在高强度服务器环境里测试过。应该确保供应商在这方面做过测试或者在发现错误以后能够做出响应。

避免回调。服务器调用客户端返回通常是一个注定要发生的问题。此外,MTS 编程模型不能很好地支持回调。在 Visual Basic 程序里,回调可以通过传递对象引用给服务器显式地进行,或者用 WithEvents 关键字隐式地进行。WithEvents 关键字使用连接点,因此使回调在幕后进行。

使用 RDS 组件和与记录集对象分离的 ADO ClientBatch。这样做可以将行集合传给客户端,甚至可以通过 HTTP 直接调用业务对象。IIS、MTS,以及 ASP 的结合,使您不用牺牲 Web 应用程序的任何优势,就可以构建和传统客户端/服务器解决方案一样健壮、一样功能完整的 Web 应用程序。

不要在会话或应用变量中存储 MTS 组件。MTS 把所有组件都看作是单元线程的,因此将它们存储在会话或应用程序变量中会造成性能和可伸缩性的问题。要了解更多信息,请参见 IIS 产品文档中的 Scripter's Reference。

不要在 ASP 脚本中使用 CreateObject() 来创建 MTS 对象。使用 Server.CreateObject()Server.CreateObject() 能遍历上下文并提供改良的安全性检查。只有您完全理解这样做的不同之处,而且真正需要在不同的活动中运行 MTS 组件时,才使用 CreateObject。更多信息请参见 IIS 产品文档的 Scripter's Reference。

只要可能,用值 (ByValue) 来传递参数。这比用引用 (ByRef) 来传递参数更有效。只有在您需要返回数据给客户端时才使用 ByRef 来传递参数。确保所有返回数据给脚本(传引用)的方法参数都是 Variant 类型。Visual Basic Scripting Edition (VBScript) 无法使用其他类型的参数来返回数据。

使用 New 关键字时要小心。当用于在同一项目下创建对象时,New 关键字不会使用 COM 创建方法。因此,使用 New 创建的对象不是 MTS 对象,即使它们安装在 MTS 中。

确保使用二进制兼容性。同样,对于 Visual Basic 项目,还必须设置线程模型为 Apartment

不要在客户机上开发服务器组件。在客户机上开发乍听起来似乎很方便,但是经历了几次“编译组件,在客户机上注销组件,复制到服务器,在 MTS 上刷新组件,再输出包以生成客户端输出可执行文件,在客户机上运行客户端的输出可执行文件,然后运行客户端程序”过程,再在此过程中处理所有的问题,您就会想在服务器上开发了。

避免用组件代码来实现安全性。例如,用 IsCallerInRole 可以实现方法级安全性。但这意味着安全性管理没有完全独立于组件的实现。像角色名改变这样的管理性改变就必须使组件代码发生变化。

编译时打开符号调试信息。否则,您就无法从 Dr. Watson 的转储中得到有用的信息。像 100% CPU 负载、进程挂起(无响应进程)、进程崩溃等情况只有当获得符号调试信息时才能解决。

调试技巧

Visual Basic 在集成开发环境 (IDE) 中有强大的解释型调试器。但是,Visual Basic 6.0 以后,可以很容易地在 IDE 中直接调试组件。 所以不再需要用 Visual C++ 或 WinDBG 来调试组件了。

使用大运行时或虚拟机的语言(比如 Visual Basic 或 Java)跟踪错误都比较困难,因为在您工作的层次之下有很多错误正在运行。此外,使用封装了底层 API(如ActiveX 数据对象 (ADO)、远程数据对象 (RDO),以及Oracle Power 对象等)的库会使情况变得更复杂。您可能会认为这些库没有错误,但是事实恰恰相反,而且由于没有源代码和符号,找出这些错误非常困难。最后,在 MTS 环境下,运行时和封装能够使编程更方便,但会造成性能和功能上的问题。一个此类例子是很多数据访问对象要执行的数据库系统表的查询。这样做可以使编程更为容易,但也会造成数据库的严重阻塞。

在 MTS 环境下调试 VB 的必要条件如下:

要求 Visual Basic 6.0 或以上版本。

要求 Windows NT 4.0 Service Pack 4 (SP4) 或以上。Windows 95 或 Windows 98 不支持 MTS 调试。

您正在调试的 Visual Basic Class 应该将 MTSTransactionMode 属性设置为除 0—NotAnMTSObject 以外的其他值。

必须在项目里编译(构建 DLL)及设置二进制兼容性。

以下步骤解释了如何创建和调试简单的 Visual Basic MTS 组件:

打开一个新的 Visual Basic ActiveX DLL 项目。

重命名 ProjectNameprjMTSDebug,并且重命名 Class1clsMTSDebug

设置 clsMTSDebug 的事务属性为 1. No Transactions

为 clsMTSDebug 添加如下代码:

Public Function Sum( Val1 As Integer, Val2 As Integer) As Integer
Sum = Val1 + Val2
End Function 

编译这个 DLL。

设置此项目为二进制兼容。(同时,设置 Retain in MemoryUnattendedExecution 并选中 Create Symbolic Information 复选框)。

创建一个名为 MTSDebug 的新 MTS 包。

将 DLL 添加到包里。

在 VB IDE 中按下 F5 运行项目。接受默认设置并点击 OK

创建并添加该 ASP 到您的一个虚拟目录中。

       Dim Obj
Set Obj = Server.CreateObject("prjMTSDebug.clsMTSDebug")
Response.Write Obj.Sum(2,3)
Set Obj = Nothing 

放置一个断点到 Sum 函数中(在 Visual Basic IDE 中)。

在浏览器中运行这个 ASP 页面。程序在断点处停止。

要经常检查事件日志。MTS、IIS 以及 ASP 记录了很多错误情况。跟踪各种类型的错误通常是非常有帮助的。(参见知识库文章 Q262187,INFO:Interpret the Microsoft Transaction Server Events in the Event Log )。

有时存在用以上方法无法简单捕捉的错误。跟踪挂起和性能问题是很有意思的。在跟踪之前,必须检查两件事情:CPU 利用率和数据库阻塞。如果在 MTS 服务器和数据库服务器上 CPU 利用率都正常,数据库阻塞通常是主要原因。发现根本原因需要考虑数据库和 ODBC 日志和记录。如果 CPU 利用率在一台机器上出现高峰,请开始查找瓶颈。对于这个问题,没有简单的解决办法。必须检查每件事情:可能是数据库服务器的磁盘利用问题、对象太大的表现、对必需的服务器硬件估计不足,等等 — 这已经超出本文的范围了。

跟踪零星的异常情况也是一种耗时而不太令人愉快的经历。MTS、ASP 或 COM 环境一般通过错误陷阱、记录事件、必要时清除来处理异常。也可以通过运行附带调试器的应用程序来捕捉这些异常。尽管您可以调试这些异常,你也可以简单地调用产品支持。准备在机器上安装符号、调试器,甚至 RAS。知识库文章 Q286350 HOWTO:Use Autodump+ to Troubleshoot "Hangs" and "Crashes",应该能给你一个初级指导。

IIS 线程和安全性问题给 ASP 页面的组件调试增加了又一层困难。但是,脚本调试器和以上的调试代码可以使在应用程序进程中调试代码变得容易的多。 复制 ASP 代码到 Visual Basic 项目,并创建一个可用来调试组件的客户端可执行文件是很有用的(有时也是必要的)技巧。 这对于开发 ASP 脚本和 Visual Basic 组件也特别有用。总体来说,Visual Basic 仍然是创建和测试 Visual Basic 代码最好的编辑器。

posted @ 2005-06-11 18:31  vboy  阅读(1254)  评论(0编辑  收藏  举报