Total votes: 3
Print: Print Article
Please login to rate or to leave a comment.
Published: 13 Jun 2007
In this article I'm going to describe the bridge between managed and unmanaged worlds and how the two collaborate to set up the processing environment needed by ASP.NET requests to be processed.
In the previous as well
as first article of this series I've introduced the first steps
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
IIS deal with incoming
requests until they finally dispatch them to an unmanaged
aspnet_isapi.dll, which acts as a bridge between the
web server and the managed
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,
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
This is the bridge between the unmanaged and managed world and is the
least documented part of all the
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
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.
Profiler, a commercial profiler for .NET Applications. A free
time limited version is available too.
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,
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
the black magic occurs through a bunch of unmanaged
COM interfaces calls
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
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
- Handling and processing of the request - accomplished by the
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
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
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
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
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
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
AppDomain. Actually, the highlighted line
shows that there are two instances of the
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
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
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
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
However, it shows clearly the two routes followed when creating the two
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
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
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
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
AppDomain class, the one used to host the web
application targeted by the request.
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
architecture, but before approaching the fun part I wanted to introduce
some core topics.
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
extension - and the managed world, represented by the
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
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.
Sorry, no bio is available
This author has published 10 articles on DotNetSlackers. View other articles or the complete profile here.
Other articles in this category
IIS FTP User Isolation - Week 46
This week we walk through the five isolation modes to gain a full understanding of the IIS FTP metho...
FTP Firewall settings, Active vs. Passive, and FTPS Explicit vs. Implicit Week 47
Understanding Active and Passive mode for FTP is useful for troubleshooting and ensuring that the fi...
Q&A. DNS Load Balancing, Google and Geo-location, CDNs-Week 50
This week answers two Q&A questions from viewers. DNS Load Balancing and then some discussion and a ...
Q&A. What’s new in IIS8, Perf, Indexing Service–Week 49
This week I'm taking Q&A from viewers, starting with what's new in IIS8, a question on enable32BitAp...
IIS FTP Troubleshooting - Week 48
This lesson covers ways to troubleshoot IIS FTP. When it works, it works well, but if you run into i...
Please login to rate or to leave a comment.