The official Fatica Labs Blog! RSS 2.0
# Saturday, November 24, 2007

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.

Saturday, November 24, 2007 3:37:00 AM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback

Archive
<September 2010>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789
About the author/Disclaimer

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

© Copyright 2010
Felice Pollano
Sign In
Statistics
Total Posts: 67
This Year: 41
This Month: 2
This Week: 0
Comments: 36
This blog visits
Locations of visitors to this page
All Content © 2010, Felice Pollano
DasBlog theme 'Business' created by Christoph De Baene (delarou) and modified by Felice Pollano