How to use unregistered COM components from ASP .Net Applications
ASP .Net 1.x has built-in support for Windows unmanaged (win32) side-by-side functionality. ASP .Net 2.0 dropped that support. There is no built-in mechanism to isolate access to unmanaged resources. It is still possible to to isolate ASP .Net 2.0 and higher applications, but some additional steps are required. In the past we suggested that an activation context could be activated and deactivated during an ASP .Net request processing using HTTP modules. In the end this approach does not work because ASP .Net may switch win32 threads during page processing. This results in no activation context or a wrong activation context on the thread processing this request and the thread with the desired activation context performing some other tasks.
There is no way to reliably intercept win32 thread switches in ASP .Net and, therefore, there is no way to turn win32 activation context on and off for the entire application. There are two possible solutions:
- Programmatically activate and deactivate activation context for the duration of a COM call.
- Activate the win32 activation context for the entire process (IIS application pool).
These solutions are not exclusive and can be used together to provide a default manifest for the entire application pool and change it as necessary during the web application processing.
Programmatic manipulation of the activation context requires using the Win32 SxS APIs. They can be called using .Net interop facilities. The calls are quite straightforward but it is important to keep track of side-by-side cookies (not related to HTTP cookies) and deactivate the contexts in the proper order. See How to Use the Activation Context API for more details and examples.
Setting the activation context for the entire process is similar to creating an application manifest for the executable that created the process. The difference is that if there is a manifest for the process, every instance of this process gets the same process default activation context and we are free to use any manifest for each process instance when we do this programmatically. Another difference is that the program manifest is activated before any DLLs are loaded which means that loading static imports is affected by the activation context. If the process default activation context is set programmatically it is set after all static DLLs have been loaded.
The process default activation context is always searched if the current activation context does not contain the definition of the required resource (DLL, CLSID, ProgID etc.) So it is possible to place common definitions in the process default activation context and only activate another activation context if a special or rarely used resource is necessary.
Once the process activation context is set, it cannot be removed or changed in any way and it is immediately effective for all threads in this process.
How to set the process default context in ASP .Net
The process default activation context can be set at any time, as long as it has not yet been set. We could use any piece of code executing in the current application pool to perform this task. We suggest using an HTTP module's Init method. Such approach does not require any changes in the web application itself, uses a documented ASP .Net behavior, guarantees creation of the activation context quite early in the ASP .Net cycle and only executes when HTTP modules are being initialized - does not impact performance by executing the code on every web request.
An example HTTP module that creates the process default activation context for the application pool is included in Manifest Maker examples. Read more about the example.
The module only
implements the Init method and uses hard-coded manifest name webapp.manifest
.
You can use this module as-is or you can build your own HTTP module that
implements a more elaborate logic of creating the application context. One such
improvement could be using the web.config file to store information on the
manifest and assembly root folder. It would then be possible to define a common
library of assemblies in some folder on the local machine and then have multiple
applications reference this common set of assemblies.
Please contact us at https://www.manifestmaker.com/aboutus.htm if you would like us to build a more elaborate side-by-side solution designed for your needs.
The aspnet20sample
example contains an example project with an appropriate
HTTP module source code and ready to use binaries. Read more
about the example.
This solution can be used with existing ASP .Net applications including
precompiled and non-updateable. No changes to the application are required, only
the webapp.config
file needs to be created or modified.
To configure the example HTTP module to create a process default activation context for an application pool executing ASP .Net applications:
- Make sure that the IIS application pool host process
w3wp.exe
does not have an external manifest (C:\WINDOWS\system32\inetsrv\w3wp.exe.manifest
must not exist).
Note that Server 2008 R2 and Windows 7 (IIS 7.5) broke the rules and added an embedded manifest to w3wp.exe. This is fixed in Service Pack 1, see article KB976932. - Determine which ASP .Net web applications need to use the same activation context. They all may, but do not need to, be configured to use the same application pool. It is important that no other web applications should use the same application pool. Remember: this is a process default activation context - all applications in this process will use the same context.
- If you are using the HTTP module included in the Manifest Maker example, we recommend that you configure one application per application pool. Otherwise it is going to be difficult to manage versions of assemblies used by the various applications.
- Create the necessary application pool and configure IIS so that the selected application uses the designated application pool.
- Create a private or shared assembly (or assemblies) with the components you need to use.
- Install these assemblies on the web server; copy to a subdirectory of the application directory if private, install with MSI if shared.
- Create a private assembly referencing all the above private and shared Win32 assemblies. Name the project
webapp
which will make the manifest namewebapp.manifest
(see note below). - Copy this manifest to the application directory on the server.
- Copy the HTTP activation context module to the application's
bin
folder. As stated above, you can write your own module or you can use the module provided in Manifest Maker examples:C:\Program Files\Maze Solutions\Manifest Maker\Examples\aspnet20sample\AspManifestHelpers\bin\Release\AspManifestHelpers.dll
. Make sure to use theRelease
build as shown above. - Edit the application's
web.config
file:- In the
<configuration>
section find (or add) section<httpModules>
- in the
<httpModules>
section add this entry (use your names, if you used your own module):
<add name="HttpModule_ProcessManifest" type="MazeSolutions.AspManifestHelpers.HttpModule_ProcessManifest, AspManifestHelpers"/>
- In the
At this point ASP .Net will load the HTTP module and will call the
Init
method during the module initialization. The module
provided with Manifest Maker creates the activation context and sets it as the
process default in this method. The activation context is
never released - process default activation context is only released when the
process terminates. In case multiple applications are configured to use the same
application pool and more then one of them uses this module, it ignores errors
resulting from attempts to set the process default activation context after it
has already been set.