General Architecture
As ASP .Net initializes its environment, it loads
configured HTTP modules.
We add our own HTTP module to this list and when ASP .Net calls our Init
method we create the process default activation context and do not register any
handlers - we do not want to be called again. Normally the Init method is only
called in an application, but if multiple applications are configured to use the
same application pool and they try to set the process default activation
context, all subsequent calls will fail. We detect the situation when the
CreateActCtx() API fails because the context is already set and we ignore this
error. It may be a good idea to crash the application instead of masking the
error if you want to enforce a clean and well-defined environment with only one
application per application pool.
Creating the HTTP Module
Examples distributed with Manifest Maker include an HTTP module to manipulate the application's activation context. The project is normally installed inC:\Program Files\Maze Solutions\Manifest Maker\Examples\aspnet20sample
.
This is an ASP .Net 2.0 class library and an example web application.
The HTTP module is implemented in the HttpModule_ProcessManifest
class. The Init method is:
// ---------------------------------------------------------------------- // Create the 'process-default' activation context // ---------------------------------------------------------------------- public void Init(HttpApplication application) { // NOTE: We do not hook any events, no need to. Once we set the process // -default activation context our job is done. string path = AppDomain.CurrentDomain.BaseDirectory; string file = Path.Combine(path, "webapp.manifest"); UInt32 dwError = 0; bool bOK = ActivationContextHelper.CreateProcessContext(file, AppDomain.CurrentDomain.BaseDirectory, out dwError); // This is an error and we must make sure it does not go unnoticed if (!bOK && ActivationContextHelper.ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET != dwError) { string err = string.Format("HttpModule_ProcessManifest.Init: Cannot create process-default win32 sxs context, error={0} manifest={1} url={2}", dwError, file, application.Context.Request.Url); System.Diagnostics.Trace.WriteLine(err, "HttpModule_ProcessManifest"); ApplicationException ex = new ApplicationException(err); throw ex; } if (application.Context.IsDebuggingEnabled) { string state = (bOK) ? "Activation context created." : "Activation context already existed."; string msg = string.Format("{0}; Init; manifest={1}; {2}", System.DateTime.Now.ToString(), file, state); System.Diagnostics.Trace.WriteLine(msg, "HttpModule_ProcessManifest"); } }
The ActivationContextHelper
class performs the activation context
creation. The manifest file name is hard-coded as webapp.manifest
, but
there is no reason why it could not be different or somehow configured. Your web.config
file should look somewhat like this:
<?xml version="1.0"?> <configuration> <system.web> <httpModules> <add name="HttpModule_ProcessManifest" type="MazeSolutions.AspManifestHelpers.HttpModule_ProcessManifest, AspManifestHelpers"/> </httpModules> </system.web> </configuration>
Of course there may be other settings, we only included here entries relevant to this particular case.
Running the HTTP Module Example
This example is not dependent on IIS because it does not use any functionality specific to IIS. It works both in IIS and in the Visual Studio development server. However the development web server installed with Visual Studio (WebDev.WebServer20.exe, WebDev.WebServer40.exe) has an embedded manifest and cannot be used in this manner unless you modify the executable and remove the embedded manifest resource and rename or delete the external manifest (WebDev.WebServer20.exe.manifest, WebDev.WebServer40.exe.manifest).
To run the example open the project (aspnet20sample.sln) using Microsoft
Visual Studio. First set the DropInManifest
as the startup project
then run the project. Your will get output similar to this:
Press this button to run the test:
Label
Now click the button. The text "Label" changes resulting in:
Press this button to run the test:
C:\Program Files\Maze Solutions\Manifest Maker\Examples\aspnet20sample\DropInManifest\aspnet.sample.assembly\sampleDLL.dll
The DLL was loaded from the private assembly and the COM object was successfully accessed.
Note: Visual Studio development server has manifests that need to be removed, see above. Use IIS if you do not wish to modify development web server installation.
To verify that this is really working as expected, remove the above HTTP module from web.config
and run the project
again. This time you get the familiar error message:
Retrieving the COM class factory for component with CLSID {4D880EAB-BF35-423A-A859-B1D9F2AC4CC1} failed due to the following error: 80040154.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Runtime.InteropServices.COMException: Retrieving the COM class factory for component with CLSID {4D880EAB-BF35-423A-A859-B1D9F2AC4CC1} failed due to the following error: 80040154.
Source Error:
Stack Trace:
_Default.Button1_Click(Object sender, EventArgs e) +13
System.Web.UI.WebControls.Button.OnClick(EventArgs e) +75
System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +98
System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +7
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +11
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +33
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +4919
Version Information: Microsoft .NET Framework Version:2.0.50727.1433; ASP.NET Version:2.0.50727.1433
If webapp.manifest
does not exist in the web application directory, the HTTP module throws an exception:
HttpModule_ProcessManifest.Init: Cannot create process-default win32 sxs context, error=2 manifest=C:\Temp\Asp.Net.20\DropInManifest\webapp.manifest url=http://localhost:1499/DropInManifest/default.aspx
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ApplicationException: HttpModule_ProcessManifest.Init: Cannot create process-default win32 sxs context, error=2 manifest=C:\Temp\Asp.Net.20\DropInManifest\webapp.manifest url=http://localhost:1499/DropInManifest/default.aspx
Source Error:
Stack Trace:
MazeSolutions.AspManifestHelpers.HttpModule_ProcessManifest.Init(HttpApplication application) +387
System.Web.HttpApplication.InitModulesCommon() +66
System.Web.HttpApplication.InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers) +1006
System.Web.HttpApplicationFactory.GetNormalApplicationInstance(HttpContext context) +259
System.Web.HttpApplicationFactory.GetApplicationInstance(HttpContext context) +114
System.Web.HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr) +350
Version Information: Microsoft .NET Framework Version:2.0.50727.1433; ASP.NET Version:2.0.50727.1433