ASP.NET Assembly Loading

18892159 Although developers often use the terms interchangably, there is a difference between a .NET Application Domain [microsoft.com] and an ASP.NET Application Pool [microsoft.com]. Regular .NET applications load assemblies into an application domain on demand.

ASP.NET has special behavior that will automatically load all assemblies in the /bin directory when the application domain loads or reloads.

An ASP.NET application domain will unload when any one of the following occurs:

  • An update to web.config, machine.config or global.asax
  • Any updates to the contents of the bin directory
  • Exceeding the threshold specified by the config compilation numRecompilesBeforeAppRestart
  • Changing physical path of the virtual directory
  • An update to the CAS
  • Restart of the web service
  • An application sub-directories is deleted

Here is a simple script you can use to see what is currently loaded in an ASP.NET application domain:


<%@Page Language="C#"%>
<html>
<head>
<title>Currently Loaded Assemblies</title>
<style type="text/css">
table {border-collapse:collapse;}
td {vertical-align:top;border: 1px solid;margin:0px;padding:3px;}
th {vertical-align:bottom;border: 1px solid;background-color:#cccccc;margin:0px;padding:3px;}
</style>
</head>
<body>
<%
AppDomain currentDomain = AppDomain.CurrentDomain;
//Once monitoring CPU and memory of application domains in the current process is enabled, it cannot be disabled.
//System.AppDomain.MonitoringIsEnabled=true;
Response.Write("<table><tr><th>Current Domain</th><td>");
Response.Write(currentDomain.FriendlyName);
Response.Write("</td></tr><tr><th>Application Trust</th><td>");
Response.Write(Server.HtmlEncode(currentDomain.ApplicationTrust.DefaultGrantSet.ToXml().ToString()));
Response.Write("</td></tr><tr><th>Dynamic Directory</th><td>");
Response.Write(currentDomain.DynamicDirectory);
Response.Write("</td></tr><tr><th>Relative Search Path</th><td>");
Response.Write(currentDomain.RelativeSearchPath);
Response.Write("</td></tr>");
if (System.AppDomain.MonitoringIsEnabled)
{
    Response.Write("<tr><th>Total Processor Time</th><td>");
    Response.Write(currentDomain.MonitoringTotalProcessorTime);
    Response.Write("</td></tr><tr><th>Total Allocated Memory</th><td>");
    Response.Write(currentDomain.MonitoringTotalAllocatedMemorySize);
    Response.Write("</td></tr><tr><th>Survived Memory</th><td>");
    Response.Write(currentDomain.MonitoringSurvivedMemorySize);
    Response.Write("</td></tr>");
}
Response.Write("</table>");
System.Reflection.Assembly[] assems = currentDomain.GetAssemblies();
Response.Write("<p>Currently Loaded Assemblies</p>");
int i=1;
Response.Write("<table><tr><th>#</th><th>Full Name</th><th>GAC</th><th>Dynamic</th><th>Code Base</th><th>Location</th></tr>");
foreach (System.Reflection.Assembly assem in assems)
{
    Response.Write("<tr><td>");
    Response.Write(i);
    Response.Write("</td><td>");
    Response.Write(assem.FullName);
    Response.Write("</td><td>");
    Response.Write(assem.GlobalAssemblyCache);
    Response.Write("</td><td>");
    Response.Write(assem.IsDynamic);
    Response.Write("</td><td>");
    try{
        Response.Write(assem.EscapedCodeBase);
    }catch{}
    Response.Write("</td><td>");
    try{
        Response.Write(assem.Location);
    }catch{}
    Response.Write("</td></tr>");
    i++;
}
Response.Write("</table>");
%>