If you've ever poked around the 'Temporary ASP.NET Files' directory on a machine that was hosting an ASP.NET 2.0 Web site, you've probably seen class definitions with the name FastObjectFactory_app_web_... that ASP.NET generates as part of the request process. I've often wondered what the real purpose of this class was, and think I've finally come upon the answer, after a little spelunking.
First of all, FastObjectFactory classes are generated on a per-assembly basis, so by default, you will see one FastObjectFactory class defined per physical directory of your site. Here's a sample definition from a site with two .aspx files in it, Default.aspx and Page2.aspx:
internal class FastObjectFactory_app_web_zlhdxrok
{
private FastObjectFactory_app_web_zlhdxrok()
{
}
static object Create_ASP_page2_aspx()
{
return new ASP.page2_aspx();
}
static object Create_ASP_default_aspx()
{
return new ASP.default_aspx();
}
}
Note that it contains two static methods that return generic object references, one for each of the pages in my site. The name of the class itself is decorated with the assembly name into which this factory class and the accompanying page2_aspx and default_aspx classes will be compiled. This is our first clue. In fact, if you make a change to one of the pages, you will notice that it generates a completely new FastObjectFactory class, with the name again decorated with a new assembly string (like FastObjectFactory_app_web_cdcab7d2).
The second clue, is the name itself - FastObjectFactory - inferring it must be faster for allocating objects than some other technique.
First, a little background. In ASP.NET 1.1, whenever you changed a .aspx file (say default.aspx), ASP.NET compiled a new assembly with a new definition of the page class (ASP.default_aspx in this case). Instead of discarding the AppDomain hosting your application to remove the old version of ASP.default_aspx, as you might suspect, it actually left the old assembly loaded and loaded the new one along-side. As long as there is no use of the type ASP.default_aspx, there will be no ambiguity having two types with the same name in separate assemblies. I always assumed that they did something like:
Assembly asm = Assembly.Load("f-u8au0h");
Page pg1 = (Page)asm.CreateInstance("ASP.default_aspx");
to create pages from their respective assemblies.
In 2.0 this behavior doesn't change, you can still modify .aspx (or their associated code behind files) without having your AppDomain unloaded (which causes in proc session state to be discarded among other potentially troublesome things). But, I suspect they now use these FastObjectFactory classes to do the creation. I haven't actually gone digging to find the instantiation code, but I suspect it looks something like:
Assembly asm = Assembly.Load("app_web_zlhdxrok");
Type t = asm.GetType("FastObjectFactory_app_web_zlhdxrok");
MethodInfo mi = t.GetMethod("Create_ASP_default_aspx", BindingFlags.Static | BindingFlags.NonPublic);
Page pg = (Page)mi.Invoke(null, null);
Now, if the MethodInfo structure is cached, this method of instantiation is about 50% faster than calling CreateInstance directly on the assembly (which I calculated by running some stress tests myself), so the FastObjectFactory should in fact live up to its name and provide a faster mechanism for Page creation.
By the way, if you want to display all of the loaded assemblies in your AppDomain in an ASP.NET 2.0 web app, try calling the following method (it also prints out all of the types housed in an assembly for those assemblies named 'App_Web...' which should be the root of all assembly names for your pages, user controls, master pages, etc.):
public static void DumpAssemblies()
{
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
HttpContext.Current.Response.Output.Write("<h3> {0} </h3>", asm.FullName);
if (asm.FullName.Contains("App_Web"))
{
foreach (Type t in asm.GetTypes())
{
HttpContext.Current.Response.Output.Write(" {0}<br />", t.FullName);
}
}
}
}
Then once you're up and running, change one of your pages and re-hit the site. You should see multiple assemblies loaded with the same type definitions (but ASP.NET is now accessing the more recently compiled version). This behavior is the same for master pages and user controls as well.
Posted
Oct 19 2005, 12:37 PM
by
fritz-onion