July 28, 2011, 12:26 p.m.
posted by roni
In our first example of the code-behind technique, we compiled an assembly containing the code-behind class and deployed it in the /bin directory of our ASP.NET application. Our page was then able to reference the class that was added to the assembly via the Inherits attribute of the Page directive. Assemblies deployed in the /bin directory are implicitly available to all pages of that application because they are added to the list of referenced assemblies during page compilation. This is a convenient mechanism not only for deploying code-behind classes, but also for deploying utility or business-logic classes that may be useful across all pages in an application.
To see an example, suppose we have built a utility class to convert temperature from Fahrenheit to centigrade and back again, as shown in Listing 1-12. To deploy this class as a utility class that would be universally accessible among all the pages within our application, we would compile it into an assembly and deploy the assembly in the /bin directory of our application. The compilation of every .aspx file in our application would then include an implicit reference to this assembly. Listing 1-13 shows a sample page using our utility class.
' File: TempConverter.vb Public Class TempConverter Shared Public Function FahrenheitToCentigrade(val As Double) _ As Double Return ((val-32)/9)*5 End Function Shared Public Function CentigradeToFahrenheit(val As Double) _ As Double Return (val*9)/5+32 End Function End Class
<!-- File: TempConverter.aspx --> <%@ Page Language='VB' %> <html><body> <h2>32 degrees Fahrenheit is <%= TempConverter.FahrenheitToCentigrade(32)%> degrees centigrade</h2> </body></html>
In traditional ASP applications, components used by pages and deployed in this fashion were notoriously difficult to update or replace. Whenever the application was up and running, it held a reference to the component file; so to replace that file, you had to shut down IIS (temporarily taking your Web server offline), replace the file, and restart IIS. One of the goals of ASP.NET was to eliminate the need to stop the running Web application whenever components of that application need to be updated or replaced—that is, updating an application should be as simple as using xcopy to replace the components on the Web server with the new updated versions. To achieve this xcopy deployment capability, the designers of ASP.NET had to ensure two things: first, that the running application not hold a reference to the component file; and second, that whenever the component file was replaced with a new version, that new version was picked up with any subsequent requests made to the application. Both of these goals are achieved by using the shadow copy mechanism provided by the Common Language Runtime (CLR).
Shadow copying of assemblies is something you can configure when you create a new application domain in .NET. The AppDomainSetup class (used to initialize an AppDomain) exposes a Boolean property called ShadowCopyFiles and a string property called CachePath, and the AppDomain class exposes a method called SetShadowCopyPath() to enable shadow copying for a particular application domain. The Boolean property turns the mechanism on for a particular application domain, the CachePath specifies the base directory where the shadowed copies should be placed, and the SetShadowCopyPath() method specifies which directories should have shadow copying enabled.
ASP.NET creates a distinct application domain for each application it hosts in its worker process; and for each application domain, it enables shadow copying of all assemblies referenced in the /bin directory. Instead of loading assemblies directly from the /bin directory, the assembly loader physically copies the referenced assembly to a separate directory (also indicated in the configuration settings for that application domain) and loads it from there. This mechanism also keeps track of where the assembly came from, so if a new version of that assembly is ever placed in the original /bin directory, it will be recopied into the "shadow" directory and newly referenced from there. Figure shows the shadow copy mechanism in action for an ASP.NET application.
In addition to shadow copying of assemblies, ASP.NET needs the ability to create and load assemblies on the fly. The first time an .aspx page is referenced, as we have seen, it is compiled into an assembly and loaded by ASP.NET. What we haven't seen is where those assemblies are located once they are compiled. Application domains also support the concept of a "dynamic directory" specified through the DynamicBase property of the AppDomainSetup class, which is a directory designed for dynamically generated assemblies that can then be referenced by the assembly loader. ASP.NET sets the dynamic directory of each application it houses to a subdirectory under the system Temporary ASP.NET Files directory with the name of the virtual directory of that application. Figure shows the location of dynamically generated assemblies for an ASP.NET application with a virtual directory named test.
One consequence of both dynamic assembly generation and shadow copying is that many assemblies are copied during the lifetime of an ASP.NET application. The assemblies that are no longer being referenced should be cleaned up so that disk space usage doesn't become a limiting factor in application growth. In the current release of ASP.NET (version 1.0.3705) shadow copied assemblies are removed as soon as possible after a new version of that assembly is copied, and dynamically generated assemblies that are no longer used are cleaned up the next time the ASP.NET worker process is bounced and the particular application associated with the dynamic assemblies is run again. In general, this means that you shouldn't have to worry about unused assemblies generated by ASP.NET wasting space on your machine for very long.