Troubleshooting Components Under ASP

From Mynoteswiki.com

J.D. Meier

October 25, 1999

Contents

Introduction

Diagnosing problems with COM components under Active Server Pages (ASP) technology continues to be a challenge for many developers as well as system administrators. Whether you're plagued by ghost-like errors that seem to occur only during production, or by problems that occur right before your very eyes during development, there's no doubt that analyzing the problem can be tricky. In this article, I'll provide some techniques to help isolate and correct component problems.

Common Scenarios

If you’ve worked with ASP technology for some time, you have probably run into one or more of the following scenarios:

  • Component works from Visual Basic® (or some other desktop client), but fails under ASP implementation
  • Component works during design time, but breaks during run time
  • Component fails intermittently
  • Component works on one machine, but not on another

Sound familiar? Read on.

Why Components Fail

Components can fail under ASP implementation for a number of reasons. The most common are:

  • Component is not designed for ASP technology. This is very common in typical business scenarios, where you are porting an existing application to your Internet or intranet, and the application's original components were not designed with ASP technology in mind.
  • Security Context. This is probably the number one killer.
  • Threading issues. I really should say threading COMplications here, because COM threading models throw a lot of folks for some loops and can dramatically impact your application’s performance and scalability.
  • Missing bits and pieces and Dynamic Link Library (DLL) Hell. Distributed applications are great, but sometimes when we put Humpty Dumpy together again we end up with Mr. Potato Head.

These four reasons are at the core of many component failures under ASP technology. Knowing the principles behind these issues will allow you to diagnose a broad range of problems.

Component is not Designed for ASP

The fact that a component works from a desktop client doesn’t mean it can or should be called from ASP. How do you know if you can call it from ASP? To find out, you will need to determine the following:

  • Does the component support IDispatch?

IDispatch is the COM interface through which ASP script performs automation. If the COM component was created with Visual Basic, it does. If the COM component was created with Visual C++®, you need to check. You can quickly check the type information from the component using OLE Viewer. OLE Viewer is included with Visual Studio®, or you can download it from Microsoft’s COM site: http://www.microsoft.com/com/resources/oleview.asp .

  • What is the threading model of the component?

This applies to in-process components.

The component should be apartment-threaded or marked Both and aggregate the free-threaded marshaler (FTM). The component should not be single-threaded or free-threaded. This is in the Windows NT 4 Option Pack documentation. For more on this topic, read George Reilly's "Server Performance and Scalability killers." Under IIS 5, for Windows 2000 COM+ solutions, neutral-threading is recommended. You can find read more information in the "COM+ Programming Overview" (http://msdn.microsoft.com/library/psdk/cossdk/pgintro_programmingoverview_9kjb.htm).

You can determine the threading model in the following ways

  • Check the threading model of the component in the registry. Using Regedit, inspect the ThreadingModel value under the LocalServer32 key for the component.

In Visual Basic, set the threading model in the Project Properties.

  • Does the component require a host container?

ActiveX® controls, such as those written with Microsoft Foundation Classes (MFC), expect a host container. So beware – ASP script is not a container for controls.

  • Does the component raise message boxes?

ASP code runs under a service so your component can’t pop up dialogues as in a desktop application. In fact, your system can hang on these message boxes that you don’t even see because they are on the System desktop.

  • Does the component need a specific user context?

At runtime, ASP code won’t have access to some resources depending on security context. For example, the component should not use the HKEY_CURRENT_USER (HKCU) registry hive. The HKCU corresponds to the currently logged-on user. During production, your component should not be running as the logged-on user, so accessing the HKCU hive will fail.

  • Is the component thread-safe?

Can the component be safely called by multiple threads? ASP is a multi-threaded COM client.

If it’s an apartment-threaded Visual Basic component, it’s thread-safe.

If it’s not a Visual Basic component, you’ll need to check with the original author or vendor. Retrofitting thread safety into a component can be very difficult. It’s best if a component is designed from the beginning to be thread-safe.

If you inherited the component or purchased it from a third-party vendor, and have limited information about the component, you can do the following:

  • Check whether the component was designed for ASP implementation. The author or vendor of the component should be able to answer this.
  • Call the component from Visual Basic using late binding. Late binding is when you use Dim as Object. This will test the IDispatch interface as well as tell you that the component has its necessary dependencies.

Answering the questions above may indicate that you can call the component from ASP script, but that does not mean you should. If a component was not designed with ASP implementation in mind, chances are you should not use it under ASP technology. Based on experience, I recommend the following guidelines for determining whether you should use your component under ASP technology.

  • Avoid writing components or using components that rely on Thread-local storage (TLS). In Visual Basic, for example, this would equate to Public variables in .BAS files. TLS means each thread will have a copy of the data. In a Web scenario, this can have unpredictable results. Clients on the same thread will share the data and potentially step on each other’s memory, while clients handled by different threads may have different values for the variables.
  • The component should be stateless. It should not require state info from one method call to another so that it can be created and destroyed from page-to-page. If the component needs to be stored in Application or Session scope and the component is apartment-threaded, red lights should go off.
  • Avoid directly calling components that wait for events. A component called from ASP script should return control to ASP script as fast as possible. This is a source of bottlenecks for many poorly designed Web applications. If you have a component that needs to perform some time-consuming operations or will wait for some critical event, consider using Microsoft Message Queue Server (MSMQ).
  • Beware of components that expect ASP technology defaults to be changed. Some third-party components may ask you to change ScriptingTimeouts and other ASP script settings from their defaults. Changing defaults isn’t necessarily bad, but you should investigate the impact on your server.
  • Beware of wrapped legacy components. While it’s possible to host many components originally written for desktop applications under ASP technology using COM wrappers, you need to consider the implications. Chances are the component requires state or does not have a suitable threading model for ASP implementation. I’m not saying don’t do it -- because the reality is that many developers will have their hands tied when building their solutions. I am saying take the above ASP technology guidelines into consideration.

Security Issues

To better understand the security context issue, we need to briefly explore Internet Information Service (IIS) security. IIS 4.0 has the following authentication methods:

  • NT Challenge/Response (NTLM). This option is great for your intranet but not supported by Netscape Navigator. Also, access is limited to the server machine (so you can't access UNC shares on remote computers) and you need to use non-authenticated protocols (sockets).
  • Basic Authentication. This is supported by Netscape Navigator, and it allows access to remote machines, including crossing domains. Under Basic Authentication, users will be prompted for their credentials, and account information is transferred in clear-text (Base64 encoded) over the wire.
  • Allow Anonymous. This option means the IUSR_<machinename> account will be used.

IIS 5.0 introduces Integrated Windows Authentication, which replaces IIS 4.0 ’s Windows NT Challenge/Response and does not limit access to the server machine. The question remains: “How is component security context determined?” Security context is determined through a combination of the process security, your component, and your component's Web application settings. If you know how security context is determined, it’s easier to diagnose a security issue or to work around a security problem. The following rules serve as a cheat-sheet of security context combinations.

  • Single-threaded and free-threaded components run as the local System account. As I mentioned earlier, you should not call single-threaded or free-threaded components from ASP script.
  • If the Web application does not have Run in separate memory space checked, in-process components (DLLs) marked either Apartment or Both will impersonate the IUSER_<machinename>. This will happen, by default, if you are allowing anonymous access, or the components will impersonate the authenticated account if IIS authentication is used.
  • If the Web application does have Run in separate memory space checked, in-process components (DLLs) marked either Apartment or Both will impersonate IWAM_<machinename>. This will happen, by default, if you are allowing anonymous, or the components will impersonate the authenticated account if IIS authentication is used.
  • Components in MTS Library packages follow the rules above.
  • Components in MTS Server packages will run as the user specified in the Identity tab on the package properties for the component.
  • Out-of-process components (EXEs) will, by default, impersonate the context of the launching user. In the case of an EXE launched by a Web application that does not have Run in separate memory space checked, the EXE will run as System. If the Web application does have Run in separate memory space checked, it will run as IWAM by default.

While these rules will help you make predictions about your component's security context, you may still have trouble determining security context. The following techniques can be helpful:

  • Call the GetUserName API from within the component and write it to a file or to the NT Event Log. This will return your component’s security context. If you’re using Visual Basic, you can use App.LogEvent to write to the NT Event Log.
  • Enable NT Auditing. See the following Knowledge Base (KB) article for step-by-step details: Q185874 How to Troubleshoot Permissions in Internet Information Server 4.0.
  • Use NT FileMon, RegMon, and HandleEx from http://www.sysinternals.com/ . A good tip is to open these logs in Excel and use the AutoFilter command on Excel’s Data menu to quickly filter the problem.
  • Run the component in an MTS server package.This technique helps test security context issues by allowing you to set specific identities for your component to run under. A server package launches a new instance of MTX.exe under the security context using the setting on the Identity tab of the package’s properties. In addition to a troubleshooting technique, this can also be an effective workaround for security context problems. See the following KB article for step-by-step details: Q223406 HOWTO: Create an Empty MTS Package to Add Components for ASP.

If you’d like to read more on security issues with components under IIS, be sure to read the KB article Q172925 INFO: Security Issues with Objects in ASP and ISAPI Extensions

Threading Issues

Threading can be a complex issue, and is often a factor in component problems ranging from performance to security. However, from a troubleshooting standpoint, I can keep the information pretty straightforward. You can better understand ASP threading issues by breaking them down into two fundamental parts: 1. What are the implications of threading models under ASP implementation? 2. How does ASP technology handle threads?

I have already covered the implications of different threading models under ASP during the previous discussion of Component Is Not Designed for ASP, so at this point I’ll move into how ASP handles threads.

ASP threading in a nutshell

Contrary to popular belief, ASP technology does not handle its own threads. ASP script threads are actually managed by MTS in a separate pool outside of IIS’s main thread pool. With this in mind, here are the key facts you need to know about ASP threads:

  • ASP technology has 10 threads allocated by MTS per processor by default. These 10 threads are servicing all of your user requests, so treat them well. In other words, do not store STA objects in Session, which would lock the entire Web application down to a single thread for that user’s Session. ASP code is much more efficient when any thread can process any request.
  • Each out-of-process Web application (e.g., Run in Separate Memory Space is checked) will have a separate pool of 10 threads by default.
  • The number of ASP threads per processor are bumped up by the following reg key:
  ProcessorThreadMax
  Using Regedt32, navigate to HKEY_LOCAL_MACHINE\ 
  SYSTEM\ 
  CurrentControlSet\ 
  Services\ 
  W3SVC\ 
  ASP\ 
  Parameters.

Add the DWORD value ProcessorThreadMax if it's not already there (By default, it is not). In IIS 5.0, this is the metabase setting, w3svc/AspProcessorThreadMax. Although modifying this number can be beneficial in some circumstances, usually you shouldn’t need to. In fact, throwing threads to the problem can worsen the condition because of extra context switching. For advice on fine-tuning this parameter and others, read Tuning Internet Information Server Performance .

When analyzing your threading issues, keep the following tips in mind:

  • Turn off ASP server-side debugging; otherwise, ASP code will lock down to a single thread.
  • The Visual Basic IDE is not a good debugger for diagnosing security or threading issues. The debugger uses a single thread of execution running as the interactive user.
  • In NT Performance Monitor, these three counters can be your best friend:
  • ASP Requests Executing. This counter indicates the current number of requests in progress, and is great for watching how many threads are executing concurrently.
  • ASP Requests Queued. This counter indicates the current number of requests sitting in the ASP queue.
  • ASP Requests Per Second. This counter indicates the number of ASP pages served per second. Use this to help identify bottlenecks in your application.
  • System’s Context Switches/sec. If this is more than 2 or 3,000, you probably have a "hot lock" in your component. ASP threads are all queuing up, waiting to get exclusive access to some shared resource in the component.
  • You can call the GetCurrentThreadId() API from your component to spit out the thread ID. This can help you confirm and diagnose common problems, such as serialization.
  • Simultaneous requests from the same user session are serialized. With this in mind, do not use a browser to test unless you have set browse in a new process and you have turned off cookies. Settings these options forces ASP script to treat each request as a new session. If you do not set these options, serialization will occur when you send a new request from the same session before the previous request completes, such as hitting Refresh on the browser in rapid-succession (the standard ASP test). The end result is that you will see ASP Requests Queued go up even though threads are available.
  • Use the Web Application Stress Tool (See "I Can't Stress It Enough") to simulate multiple-client access. Do not use a browser except for limited troubleshooting, such as a problem that reproduces with only a couple of users.

Books can be written about analyzing your ASP script's thread performance. In fact, they have. A great source for additional information is the IIS 4.0 Resource Kit.

Missing Bits and Pieces and DLL Hell

I’ve saved the best problem for last. You’ve stuck your component on a different machine, and it doesn’t work because either you’re missing a vital piece or there’s a different version of a dependency. You’ve already weeded out security problems using techniques presented earlier under “Security Issues.”

This is actually one of the worst problems, because diagnosis can sometimes equate to finding a needle in the haystack. As if to add insult to injury, you know that your component ran fine on your other machine. It’s easy to start thinking this particular box is against you.

The best approach to this problem is avoidance. I don’t mean deploy your solution, take your client’s money, and run. Take precautionary steps to limit or prevent this dilemma from ever occurring. The following techniques have proven helpful in reducing the frequency and severity of the problem:

  • Mirror your deployment target in terms of hardware, software, and so forth. This sounds expensive and usually is, but downtime may cost more.
  • If you’re using Visual Basic, develop your component with project compatibility until you have solidified your public interfaces.

Once you know your public interfaces, build your project with binary compatibility.

Do not change your public interfaces unless you have tight control over the deployment target. It’s possible an older version of the component will overwrite a newer one. Potentially, a client expecting the new interfaces will call methods that do not exist. Instead, create a new component with the new interfaces. For more information, read "Building, Versioning, and Maintaining Visual Basic Component."

  • Include extensive, robust error handling, error logging, and event logging for your component. You will appreciate it when the time comes.
  • Perform a manual installation of your DLLs. This will help prevent hosing your system, and will allow you to recover if things go bad during installation. To perform a manual installation, register your new DLLs using RegSvr32.Exe. If you are replacing DLLs, first, unregister the old using the /u parameter to RegSrv32.Exe, and rename the DLLs by adding an extension such as .old. You can then add your new DLLs and register them RegSvr32.Exe.

Let’s say it’s too late for problem avoidance. What can you do for problem correction? The following techniques will help peel away layers of the problem:

  • Use the Dependency Walker tool, depends.exe
  • Create simple methods within your component that you can call from a Visual Basic test EXE to test core functionality. This test is important, because it will help diagnose instantiation, security, and dependency issues all very quickly.
  • Similarly, you can also use OLE Viewer to see whether the component can even be instantiated. This will take ASP functionality out of the picture and will reduce the complexity of the problem. You need to be able to instantiate the component from OLE Viewer before you can call it from ASP script.
  • Pull out NT FileMon, NT RegMon, and NT HandleEx, as mentioned earlier under "Security Issues."

Conclusion

Armed with this information, you should be able to spot and diagnose a broad range of component problems under ASP functionality. While this ability may not razzle and dazzle your friends, it will help keep your Web application healthy and your customers happy.

J.D. Meier was born and reared on the U.S. East Coast. Since heeding Horace Greeley's advice, he has worked as a Developer Support engineer specializing in server-side components and Windows DNA applications involving MTS and ASP technology.