Felice Pollano Blog

The Official Fatica Labs Blog

About the author

Author Name is someone.
E-mail me Send mail

Recent posts

Recent comments

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010

Customizing private path and config file with CreateApplicationHost

Hosting asp.net pipeline in .NET is easy, just a call to CreateApplicationHost and we can expose some web infrastructure in our application. Unfortunately, the plain call does not satisfy some requirements:

  • We need to have a separate web.config file for the hosted asp application ( why don't use the application config file itself ? )
  • We need to create a bin subfolder containing the assembly the asp subsystem needs to load.

If we need to change this, we need  to change  the AppDomainSetup parameters for the newly created appdomain. There was a smart hack prior to ASP.NET 2.0 by Rick Stral, but does not work anymore, and just cutting some reflector output to emulate what CreateApplicationHost does internally is too complex.

The solution I propose here is Intercept AppDomain creation and setup the right parameters for us. What we need is a custom AppDomainManager, to inject in our application and let it change the domain setup parameters.

 

 

 public class Manager:AppDomainManager
{
public override AppDomain CreateDomain(string friendlyName
, System.Security.Policy.Evidence securityInfo
, AppDomainSetup appDomainInfo)
{
string s = System.Environment.GetEnvironmentVariable("AD_INTERCEPT_CREATION");
if (!string.IsNullOrEmpty(s) && s == "Y")
{
if (appDomainInfo == null)
appDomainInfo = new AppDomainSetup();
appDomainInfo.ApplicationBase = System.Environment.GetEnvironmentVariable("AD_INTERCEPT_APPBASE",EnvironmentVariableTarget.Process);
appDomainInfo.PrivateBinPath = System.Environment.GetEnvironmentVariable("AD_INTERCEPT_PRIVATE_BIN_PATH", EnvironmentVariableTarget.Process);
appDomainInfo.ConfigurationFile = System.Environment.GetEnvironmentVariable("AD_INTERCEPT_CONFIG_FILE", EnvironmentVariableTarget.Process); ;
}
return base.CreateDomain(friendlyName, securityInfo, appDomainInfo);
}

}

  We need to put this class in a separate assembly, and register it in the GAC. Both these steps are mandatory. The interceptor shown before, just check if there is a process environment variable AD_INTERCEPT_CREATION with a "Y" value. If so, it uses the AD_INTERCEPT_APPBASE,AD_INTERCEPT_PRIVATE_BIN_PATH,AD_INTERCEPT_CONFIG_FILE variables to set the app domain parameters.

Next step is making our application aware of our AppDomainManager. This is done by .NET understood environment variable.

APPDOMAIN_MANAGER_ASM = "the full name with version and public key token of the assembly containing our AppDomainManager "

APPDOMAIN_MANAGER_TYPE = "the type name of our AppDomainManager class"  

This is not a soo easy step. We need some strategy to do it automatically, just because if we set these variable after our process is started, they simple does no effect. After some searching I found the solution here. Basically the trick is: start the process, understand if our application manager is the one we want, if not, shell a new process with the environment variables set.

 Lets have an example:

 

 

static void Main()
{
AppDomainManager domainManager = AppDomain.CurrentDomain.DomainManager;
if (domainManager != null && domainManager.GetType() == typeof(MyADManager.Manager))
{
if (Environment.GetEnvironmentVariable("DEBUG_CHILD", EnvironmentVariableTarget.Process) == "Y")
{
Debugger.Break();
}
//.... "real" application code here
}
else
{
ProcessStartInfo psi = new ProcessStartInfo(Assembly.GetExecutingAssembly().Location, Environment.CommandLine);
// setup the AppDomainManager environment variables 
psi.UseShellExecute = false; 
psi.EnvironmentVariables["APPDOMAIN_MANAGER_ASM"] = "assembly containing AppDomainManager";
psi.EnvironmentVariables["APPDOMAIN_MANAGER_TYPE"] = "MyADManager.Manager";
if( Debugger.IsAttached )
psi.EnvironmentVariables["DEBUG_CHILD"] = "Y";
Process process = Process.Start(psi); 
}
}

 Please not thethat we need to check if a debugger is attached, so we can break the new process instance to attach a debugger again.

Now we almost done. Next and last step is creating the Application Host:

 

 FileInfo fileInfo = new
FileInfo(Assembly.GetExecutingAssembly().Location);
System.Environment.SetEnvironmentVariable("AD_INTERCEPT_CREATION", "Y", EnvironmentVariableTarget.Process);
System.Environment.SetEnvironmentVariable("AD_INTERCEPT_APPBASE", fileInfo.DirectoryName, EnvironmentVariableTarget.Process);
System.Environment.SetEnvironmentVariable("AD_INTERCEPT_PRIVATE_BIN_PATH", fileInfo.DirectoryName, EnvironmentVariableTarget.Process);
System.Environment.SetEnvironmentVariable("AD_INTERCEPT_CONFIG_FILE", "myapp.exe.config", EnvironmentVariableTarget.Process);
//set the app base and the config file
_host = (Host)ApplicationHost.CreateApplicationHost(typeof(Host), _virtualPath, _physicalPath);
System.Environment.SetEnvironmentVariable("AD_INTERCEPT_CREATION", "N", EnvironmentVariableTarget.Process);
_host.Configure(this, Port, _virtualPath, _physicalPath, InstallPath);

 In the example above, we created our ASP.NET pipeline sharing the application config file, and probing the application path for assembly loading. So we have nor more needing of an extra web.config file and bin subfolder.

Currently rated 5.0 by 2 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,
Posted by Felice on Saturday, November 24, 2007 4:37 AM
Permalink | Comments (1) | Post RSSRSS comment feed

Comments

DotNetKicks.com

Saturday, November 24, 2007 2:31 AM

trackback

Trackback from DotNetKicks.com

Customizing private path and config file with CreateApplicationHost

Comments are closed