A friend of mine asked me a question which reminded me a very important issue regarding STA (Single Threaded Apartment) COM objects in ASP.NET Web applications. STA COM objects were created so that most people won’t have to deal with threading issues. The COM framework itself will make sure that each call to any method in an STA COM object will be blocked so that other requests from other threads won’t be able to get into that certain method until a previous call exited it (they will be queued).

My friend tried to create an STA COM object within the web application. The COM object was suppose to access a network share on some other machine in the network.

The ASP.NET process was configured to use the default IUSR_XXX (where XXX is your machine name) user, which has little access to anything.

In order to access the network share we had to change the context of the calling thread, so my friend used the <identity> tag in the web.config to make sure each request to the page running this code will impersonate to the user specified in the <identity> tag.

The problem starts with the threading model of ASP.NET. ASP.NET threads which executes the various request it receives are MTA (Multi Threaded Apartment). When an STA COM object is created on an MTA thread, to actually being able to perform the synchronization that STA COM objects give, we will have to context switch to the default STA thread of the process (which is a dedicated thread for that purpose) and the COM object will be created there.

Here our problem starts. The <identity> tag makes sure that the thread executing the request (the MTA thread) will impersonate its security context to the user specified in the <identity> tag but our STA COM object eventually was created on the default STA thread which was not impersonate, causing it to get the security context of the process (which was IUSR_XXX – the least powerful user of all). This meant that when the STA COM object tried to access the network share it failed since it didn’t get the right credentials.

So, how can we solve this issue? There are a number of ways.

The easiest way of all is to change the user running the ASP.NET application. To do that in Windows XP or Windows 2000 you need to go to the machine.config file and change the username and password in the processModel section. It is not recommended to put your password in clear text in the machine.config. That is why Microsoft released this utility which will encrypt your username and password in the registry.

In Windows 2003, you’ll need to create a new Application Pool and make sure the identity of that pool is the needed user that can do all the necessary things, security wise, that your application needs to do.

Another option, is to use the identity flag as specified in MSDN but to add the ASPCompat attribute to the your page class (or enable it in the ASPX page as described here). This will make sure that each of your requests to that page will actually run in an STA thread instead of an MTA thread, so when creating an STA object from within this page, the object will be created on the calling thread (since we are already in an STA thread) which will have the correct identity (we are using the <identity> configuration in the web.config).

And the last option, which works in .NET Framework 1.1 SP1 and above and in .NET Framework 2.0 (though I haven’t tested it in .NET 2.0), is to add a special flag called “apartmentThreading” which essentially changes all of your page to work the same way as adding the ASPCompat attribute.

In any case, in order not to hurt performance and scalability too much, use as little STA COM objects as you can and specifically mark the pages calling these STA objects using the ASPCompat attribute. When you have to use an STA COM object, create it, use it and released it as soon as you can, preferably using Marshal.ReleaseCOMObject (which will force it to die as soon as you call this method instead of waiting for the next garbage collection. To get more information about what Marshal.ReleaseCOMObject does see my previous post).

  • Anonymous

    i had a similar issue with a web service.

    simply whenever i needed to execute methods on an STA com object.
    i launched a new STA thread with the proper security context to perform the job.

  • It’s a nice solution, but it requires you to do all the dirty work alone.

    If you simply create an STA thread, it means that for every request that comes into that page a new thread is created (unless you handle your own thread pool).

    In this case, it might be a bit more wise to add the ASPCompat attribute and make sure all of the requests that comes to that page will work on an STA thread. When ASP.NET see the ASPCompat attribute it will use the COM+ Thread Pool for the STA threads, so you get a thread pool without doing anything.

  • Anonymous

    Hi, I have the same issue with COM+ and ASP.NET2. I’m trying to impersonate a request to COM+ to access a remote share. In COM+ I do Environ(“USERNAME”) to check what user name is calling COM+ and it always returns me ASPNET (tested on XP and Win2000). I did try apartmentThreading, AspCompat and impersonate=”true” – still the same. Any ideas?

  • Hello there, Is your COM+ object written in .NET or not?
    Is it an out of process COM+ host process or does it run in process inside ASP.NET?

    If I understand correctly, you are trying to use Windows Authentication to delegate a user’s credentials down to the COM+ level and impersonate using these credentials to perform a certain operation.

    You need to make that:
    a) In IIS Windows Authentication is enabled on your applications’ folder.
    b) In ASP.NET Impersonation is enabled
    c) In COM+ this object run in-processes of the calling process and not out of process.

    I hope that will help you.

  • Just read your post. I didn’t really notice how old it was until I got to the comment section. Was wondering if most of it is still pretty valid or if it’s now obsolete? Thanks!