Introduction
In the previous as well
as first article of this series I've introduced the first steps
performed
by a generic web request
once accepted by the web server, and what route it takes when it
is identified as an ASP.NET resource request. You've seen how different
releases of IIS deal with incoming ASP.NET-related
requests until they finally dispatch them to an unmanaged Win32 component
called aspnet_isapi.dll, which acts as a bridge between the
web server and the managed ASP.NET infrastructure.
In this article I'm going to resume the discussion exactly where I left
it and start delving into the managed part of the processing environment I've
presented in the previous article as those black boxes labeled
ASP.NET Http Runtime Environment.
Note: The ASP.NET Http Runtime Environment
is sometimes also referred to as the ASP.NET Pipeline,
Http Runtime
Pipeline or a mix of these words.
Leaving the aspnet_isapi.dll extension for the managed world
In the previous article I've explained how IIS 5 and
IIS 6 manage ASP.NET requests. Regardless of
how they deal with worker processes generation, management and
recycling, all the information pertaining to the request is in the end
forwarded to the aspnet_isapi.dll extension.
This is the bridge between the unmanaged and managed world and is the
least documented part of all the ASP.NET architecture.
Note: At the moment of the writing of this article
IIS 7 has just been released with a Go Live license along with
Longhorn Server Beta 3. A lot of things will change with IIS 7, and
although these first articles have been focusing solely on previous
versions of IIS, a future article will be dedicated to changes and
improvements introduced by IIS 7.
As for the lack of documentation available on most parts of
this topic, what I'm going to explain may not be completely correct,
especially for what concerns the unmanaged parts of the infrastructure.
However, my considerations on the undocumented topics are based on some
tools which helped a lot in understanding and making sense of the inner
workings of the framework:
- Lutz Roeder's .NET
Reflector, to analyze statically and decompile the code of .NET
managed classes.
-
Microsoft CLR Profiler, to analyze the dynamic behavior of the
framework by looking at method calls, memory allocation, class
instantiation and a whole big number of other features it provides.
-
JetBrains dotTrace
Profiler, a commercial profiler for .NET Applications. A free
time limited version is available too.
-
Red Gate
ANTS Profiler, another commercial profiler for .NET
applications. A free time limited version is available.
Going back to the bridge between the unmanaged and managed worlds,
once the CLR has been loaded - either by the ISAPI Extension in case of
IIS 6 process model or by the worker process in case of
IIS 5 process
model -
the black magic occurs through a bunch of unmanaged COM interfaces calls
that the
ASP.NET ISAPI component makes to a couple of managed classes
contained in the System.Web.Hosting namespace, the
AppManagerAppDomainFactory class and the
ISAPIRuntime class, which expose some methods via
COM-callable interfaces.
Note: The Common Language Runtime - CLR -
represents the execution environment of every .NET application. It's
what actually provides both environment and services for running
managed applications. It has to be hosted inside a Win32 process and
ASP.NET is one of the available hosts for the CLR provided by the
.NET framework. More specifically, the ASP.NET worker process
(aspnet_wp.exe in IIS 5 and w3wp.exe in IIS 6) is the process who
hosts the CLR in ASP.NET.
Before delving into the technical details of the interactions
occurring between these classes let's see on the surface what actually
happens for a request to be processed. I have introduced the previous two
classes because the entry points in the processing of a request
can be roughly grouped into two categories:
- Setup of an
AppDomain, in case one doesn't exist
yet, to represent the application
to which the request is targeted - this is accomplished by
the AppManagerAppDomain class.
- Handling and processing of the request - accomplished by the
ISAPIRuntime class.
Though the two categories are equally important, the first consists
of interactions which are supposed to happen without the interference of
the developer and which concern mostly the hosting environment of the
application, while the second is the most configurable part of the
infrastructure, which I will delve into completely in the following
article of this series.
Under another point of view, the first category comprises
operations performed only once during the lifecycle of an application,
that is, at startup, while the second consists of interactions occurring
at each request targeting that specific application.
Setting up an AppDomain
As seen in the previous article, an ASP.NET application
is reserved and wrapped into an entity called Application Domain, aka
AppDomain, which turns out to be represented by a class of the
ASP.NET architecture, the
AppDomain class. When a request to a particular application
arrives, an AppDomain has to be setup, if it doesn't exist.
This usually happens if the incoming request is the first one targeting
that particular application, or if for some reasons the corresponding
AppDomain has been shut down, which may happen for several
reasons that I will talk about later. Note that only one AppDomain exists for a
single ASP.NET application, which is itself mapped one-to-one with an IIS application - either
created over a physical/virtual directory. So how does an instance of this class get created?
Figure 1: Call stack generated by the creation of an AppDomain
instance as shown by JetBrains dotTrace Profiler

(
Click for larger image)
Using Reflector it's possible to realize that the AppDomain
class has a private constructor which throws a
NotSupportedException exception. Therefore this is obviously
not the way to go.
The entry point for the instantiation of an AppDomain is in
fact the
AppManagerAppDomainFactory.Create method. To find it out it's
necessary to use a profiler which keeps track of the call stack
generated when instantiating the object. Figure 1 displays a
screenshot of JetBrains dotTrace Profiler, which shows the call stack
generated to instantiate the AppDomain of a web application
hosted on IIS. A lot of classes participate in the process, but it's
something a developer will probably never have to put his hands on.
Note that the AppManagerAppDomainFactory class is
instantiated only once during and by the CLR initialization process. As
its name suggests, it's used as the entry point for creating
AppDomains as well as other critical objects.
Figure 2 shows the same call stack as the previous image, this time
captured from the output of the Call Tree view of Microsoft CLR
Profiler. This provides some more information about the instantiation of
the AppDomain. Actually, the highlighted line
shows that there are two instances of the AppDomain class
created by the principal thread.
Figure 2: Call stack generated by the creation of an AppDomain
instance as shown by the Call Tree view of Microsoft CLR Profiler

(Click for larger image)
So, how does this additional instance get created, and why? Unluckily
it's not an easy question. The call stack shown in the previous images
represents the steps followed for instantiating the AppDomain
which corresponds to the actual application being executed, so this
additional instance looks like a helper object used for some purpose
which is difficult to understand - as far as I can guess, it's used to
host all the objects which don't belong to a specific application, and
therefore are hosted in an isolated AppDomain, like the
AppManagerAppDomainFactory class. As for the
AppManagerAppDomainFactory class, this helper AppDomain
is instantiated only once during and by the CLR initialization, and very
very early during this stage, as shown in Figure 3.
Figure 3: Order and allocation method of the additional AppDomain
instance

Figure 3 represents a screenshot of Red Gate ANTS Profiler. It shows
that the additional AppDomain instance is created very
early and during the initialization of the CLR. It is obviously created
earlier than the
AppManagerAppDomainFactory class, since it is probably its
container. The ID of the singleton
AppManagerAppDomainFactory instance, in fact, in the profiling
session of the previous figure turns out to be 52.
Another way to see the instantiation process of the two
AppDomains - which I present for completeness - is the Allocation
Graph view provided by Microsoft CLR Profiler. It creates a graphical
flow representation of the classes taking place in the process, as shown
in Figure 4.
Figure 4: Instantiation of two AppDomains shown with the Allocation
Graph view of Microsoft CLR Profiler
This represents a compressed view which cuts out all the classes between
the <root> element - the CLR - and the Thread class.
However, it shows clearly the two routes followed when creating the two
AppDomain instances.
Another information about AppDomain instances that can
be obtained from the previous figures is that each instance occupies
exactly 100 bytes in memory. Not that it matters much, but one might
think that an AppDomain is a huge class since it has to
host an entire application. Actually, it provides a lot of services but
doesn't store a lot of data.
By now, the helper AppDomain instance has been created,
as well as an instance of the
AppManagerAppDomainFactory class, whose Create
method is the entry point of the call stack shown in figures 1 and 2.
This method is exposed and called via COM, thus unmanaged
code. The
AppManagerAppDomainFactory class implements the
IAppManagerAppDomainFactory interface, whose structure is
represented in Figure 5.
Figure 5: Structure of the IAppManagerAppDomainFactory interface

The interface is decorated with the
ComImport and
InterfaceType attribute, which bind the type to an unmanaged
interface type. When this method is called it produces the call stack of
figures 1 and 2 which in the end triggers the creation of an instance of
the AppDomain class, the one used to host the web
application targeted by the request.
Once the AppDomain is up and running all that's left to
do - and it's much more than what's been done so far - is processing the
request. This is probably the most interesting part of the ASP.NET
architecture, but before approaching the fun part I wanted to introduce
some core topics.
Summary
In this article I've introduced some very low level topics about the
ASP.NET infrastructure, those concerning the interface
between the unmanaged world - represented by the ASP.NET ISAPI
extension - and the managed world, represented by the AppDomain
hosting the web application. I've presented the mechanisms by which an
AppDomain gets instantiated and which classes take part in
the process. In the next article I will discuss of managed code only by
presenting the HTTP Pipeline, which is in my opinion the
most attractive chapter of the ASP.NET architecture, and
what actually makes ASP.NET different from all the other
web development frameworks out there. I hope you enjoyed reading this
article as much as I did writing it. My advice is to fire up some
profiler and try out this stuff by yourself, which is the best way to
fully understand how it all works.
References
About Simone Busoli
 |
Sorry, no bio is available
This author has published 9 articles on DotNetSlackers. View other articles or the complete profile here.
|
You might also be interested in the following related blog posts
ASP.NET MVC: DevExpress Mail Demo
read more
Export Word documents to XPS - Open XML Paper Specification format
read more
Bind InfoPath form to XML, Tables, SharePoint Lists & Web Services
read more
Create or Manage XPDL 1.0 & 2.1 packages using Aspose.Workflow
read more
Application Identifiers (AI) for EAN-128 barcode generation
read more
Create charts & add ad hoc capabilities to .NET Web & WinForm apps
read more
How do ASP.NET Application_ Events Work
read more
Live Mesh as an application platform
read more
Updated SilverTwit Code for MSDN Magazine
read more
Teleriks Q2 2009 Release Expands All-in-one .NET Offering
read more
|
|
Please login to rate or to leave a comment.