IIS Applications and ASP.NET Specifics
Overview
I've noticed in helping developers on the various forums and newsgroups
that there is a severe shortage of information about IIS Applications.
My last article provided some background information on IIS Applications,
applicable to classic ASP and ASP.NET, so please be sure to
read it first.
This article aims to add IIS Application details relevant only to ASP.NET
so you can avoid common problems, and also to show you a few real solutions.
Application Boundaries
An IIS Application is basically a logical web-site, isolated from all others.
This means that different IIS Applications do not share resources, just as
separate web-sites and separate Windows Applications do not share resources.
ASP.NET even loads each IIS Application into its own AppDomain automatically.
This means that not only are Application and Session variables not shared,
but also the Cache object and static (Shared in VB) variables are not shared.
Each IIS Application must also have its own Global.asax file at its app-root,
or none at all, and each app starts and stops independently of all others.
ASP.NET User Controls (.ascx) are also not shared across IIS Applications,
so they will either need to be copied to each app, or use Custom Controls.
Server.Execute/Transfer may work across IIS Applications, but there are
cases where it will fail, or where at least some odd behavior will occur.
Application Configuration
Some web.config settings are only allowed for IIS Application directories,
including authentication, machineKey, securityPolicy, sessionState, and trust.
Note that you can change authorization levels for any directory, or any page,
but authentication requires an IIS Application, ruling out xcopy deployment,
which leads to one of the most common avoidable problems I see in the forums.
Some settings (httpModules, trace) seem to be ignored for non-IIS Applications.
ASP.NET compiled assemblies are required to be in the bin directory or the GAC,
by default, but only IIS Applications automatically support bin directories.
This is another very common problem, which again rules out xcopy deployment,
since merely creating a bin directory inside a normal directory will fail.
There is a way around this problem, also applicable if you want to rename bin,
which is to modify the assemblyBinding privatePath at the IIS Application level.
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="SubDirectory\bin; OtherDirectory"/>
</assemblyBinding>
</runtime>
</configuration>
Applications and Paths
Most web developers are familiar with using relative paths for all links,
including hyperlinks, images, and stylesheets, to be able to move web pages.
One common problem in ASP.NET pages is that reusable portions are separated
out into User Controls, but this can make relative paths difficult to use.
The typical solution to this is to use web-root absolute paths instead here,
resulting in the hard-coded sub-directories that are common on ASP.NET sites.
The correct solution to this problem is to use app-relative paths instead,
which ASP.NET nicely makes possible through the use of the tilde (~) prefix.
Instead of <a href="/App/Page.aspx">, use <a href="~/Page.aspx" runat="server">.
The same ~ notation works for images also, as long as you add runat="server".
There is also a ResolveUrl method that allows you to use ~ in your own code,
which by the way is one possible way to get stylesheet paths app-relative.
Application Instances
IIS Applications start when the first page in them is requested, and continue
to run until they are stopped, either manually with the Unload button, or due
to timeouts or other constraints automatically applied in ASP.NET configuration.
It also appears that the IIS Application may timeout when the last session ends,
at least this is a typical observed behavior of shared hosting many experience,
so read this
previous article of mine for a pre-compile and keep-alive hack.
Another common misconception is that there is just one Application instance
that is loaded into memory for each ASP.NET IIS Application that is executing.
ASP.NET is multi-threaded and it creates and pools multiple copies of both the
Application object and any HttpModules that you configure in the web.config file.
This means that any variables you use in Global.asax or in HttpModules should be
static (Shared in VB) and either read-only or synchronized if writing is needed.
Applications and VS.NET
Large applications are usually separated into multiple projects in VS.NET solutions,
but VS.NET only supports one web project in each directory. This means that you
will need to break large web apps into sub-folders that correspond to web projects.
VS.NET automatically makes all new web projects into IIS Applications, but you can
use the IIS Manager to remove the App setting. Then just make sure that the main
web project at the app-root has references to all of the other sub-web projects.
Another problem with VS.NET is that there is a bug in the debugger that causes
it to get confused in the common scenario with a default.aspx page in each folder.
The work-around is difficult to setup the first time, but it does work very well.
Using Explorer, change the names of the code-behind files to something unique,
make the resx files have the same unique names, then edit the default.aspx pages
so that the codebehind attributes in the page directives point to the new filenames.
Conclusion
Hopefully I have succeeded in filling in some basic missing information about
IIS Applications and ASP.NET, as well as provided some useful tips and tricks.
My recommmendation, especially if you want to use xcopy and shared web-hosting,
is to use app-relative paths, with ~, when you develop using an IIS Application
so that you can easily deploy it to a web-site instead of using a sub-directory.
My pet peeve: please do not confuse IIS Applications with Virtual Directories.
Author Bio
Paul Wilson is a software architect in Atlanta, currently with a medical device company.
He specializes in Microsoft technologies, including .NET, C#, ASP, SQL, COM+, and VB.
His
WilsonWebForm
Control allows Multiple Forms and Non-PostBack Forms in ASP.NET.
He is a Microsoft MVP in ASP.NET and is also recognized as an ASPFriend's
ASPAce/ASPElite.
He is a moderator on Microsoft's
ASP.NET Forums, as well as one of the top posters.
He is certified in .NET (MCAD), as well as also holding the MCSD, MCDBA, and MCSE.
Please visit his website,
www.WilsonDotNet.com,
or email him at
Paul@WilsonDotNet.com.