Deployment with ASP.NET 2.0 Stock Projects
Once you've created your ASP.NET application and have it running inside the development environment for testing, the next big step is to deploy the application. When it comes to moving your Web application online there are a number of deployment models available, listed in Table 1.
Table 1: Deployment Models available in ASP.NET 20.
Requires no compilation, but requires deploying all files, including source files on the Web server. This includes code in the APP_CODE directory and any CodeBeside class source files. Relies on ASP.NET to compile the entire site at run time. You must update any files that have changed.
At the other end of the extreme is full pre-compilation with ASPNET_COMPILER.EXE. In this scenario, ASP.NET compiles all ASPX/ASCX/MASTER etc., pages, their CodeBeside classes, and all code in APP_CODE. The compiler creates a distribution of your Web site in a separate deployment directory, which you can then move to a Web server (or ASP.NET can send it for you). Since you compile everything it's possible to deploy only the files in the BIN directory plus a few marker files.
Partial compilation lies somewhere between the other two models and uses ASPNET_COMPILER.EXE to compile only the CodeBeside classes at compile time. The ASPX/ASCX/MASTER pages are left editable, which allows you to modify the markup pages on the server.
All three models have their strengths and weaknesses. Let's take a closer look.
In-place deployment is the simplest way to get a Web site online, but it's also the most insecure. With in-place compilation you essentially copy your exact development configuration to the Web server, including ASPX
markup pages and CodeBehind pages, all the code contained in APP_CODE
and any static content-like images, themes, style sheets, etc. There's no pre-compilation involved with this model and the copy process is truly one-to-one between your development environment and the Web server. ASP.NET 2.0 completely compiles the site at run time. ASP.NET uses the in-place model when you're running inside Visual Studio.
|Full pre-compilation allows you to compile all ASP.NET application code and markup.|
Although in-place deployment is the simplest format conceptually, it has a few serious shortcomings. First and foremost you have to deploy your source files, which is a security issue both for source code protection as well as for security concerns. If you put the source code on the server, the code is potentially accessible to anybody with physical access to the box. Someone else could look at the code and even change it on the server. That's good if you need to make changes, but it's obviously bad if an unauthorized person or a hacker tampers with the code. Though this may be unlikely, the potential for damage if somebody gains access to the machine is huge.
If you have a vertical application you probably don't want to ship your source code to your customers, so in-place compilation also doesn't work well if you want to keep the source code from prying eyes.
Actual deployment to the server involves simply moving the files from a development directory to the server, but it also means that anytime you make a change you have to remember which files to update on the server unless you redeploy the entire site.
|Figure 5: My ASP.NET compiler utility provides a graphical front end to the ASPNET_COMPILER command-line utility that lets you experiment with the different compiler options.|
The most common deployment scenario is full pre-compilation. In this model you use the ASPNET_COMPILER
utility or the "Web Site Publishing" feature inside Visual Studio, which uses the same compilation APIs, to pre-compile your site in its entirety. This means that all markup pages (ASPX
), CodeBeside classes, and all code in the APP_CODE
directory are pre-compiled. The compiler takes the existing Web site and publishes the site to a new directory, copying all files that relate to the site, including static files such as images and CSS files. The compiler essentially generates a complete copy of your Web site, outputting a large number of compiled files in the BIN
Pre-compilation comes in many different flavors. You can choose to compile pages into one assembly per page or compile them into a directory. You can compile with debug mode on or off. You can compile files from a physical path or an IIS virtual directory etc., (I'm not going to go through all the options here). I've provided a tool (shown in Figure 5
) that you can use to experiment for yourself and check out the output generated from the compilation. Instead I'll run through a few common scenarios that I've used to successfully deploy my applications.
The first example compiles the entire site with directory-level assemblies that are as close to a default compilation as it comes:
aspnet_compiler.exe -f -v
This takes the Virtual Directory (-v "CompilationAndDeployment") to be compiled into the output path (c:\temp\deploy\CompilationAndDeployment) forcing the directory to be recreated (-f). Figure 6
and Figure 7
show the Visual Studio Solution and the output of the BIN directory created by this compiler command line.
|Figure 6: The sample Web Project in the Solution Explorer is a small project with a few folders containing pages and controls.||
|Figure 7: The output generated by a "stock" ASPNET_COMPILER run. Output from the simple solution generates a BIN directory that contains one assembly per directory, plus assemblies for APP_CODE and a separate assembly for the Visual Basic .NET class in the C# project. Notice the .compiled marker files.||
You'll notice that the compiler recreated the entire directory structure in the output path. The root directory still contains ASPX
pages, but these pages are merely marker files that contain this text:
This is a marker file generated by the precompilation tool, and should not be deleted!
The file's actual ASPX
code file is compiled and contained in one of the assemblies in the BIN
directory. The marker file is maintained for one reason only: To support Windows Authentication. If you need to set specific Windows file rights on a directory or specific file, an actual file must exist in order for Windows Authentication to work. If you don't use Windows Authentication, you can remove these marker files.
directory itself contains a number of assemblies. The App_Web
assemblies contain compiled page and control classes, one for each directory and for each language. Remember that this project included one Visual Basic .NET page, which compiles into a separate assembly. The App_Code
assembly that contains all the code from the App_Code
directory. If you have a global.asax
file that will also use another separate assembly, as will each ASP.NET theme used in the project. The theme classes provide ASP.NET with the location of the theme directory and any linked style sheets used with a theme.
Themes are hard-coded into a pre-compiled Web application. Whatever value is configured in web.config
at compile time becomes the hard-coded default theme for the site; changing the value in web.config
has no effect after compilation. If you need to override themes in a pre-compiled application, you have to explicitly override the theme for each page in the OnPreInit()
event of the page.
You'll also notice a large number of .compiled
files in the BIN folder. The .compiled
file is a marker file for each page and control in the Web site, and identifies the class used inside the assembly. These files are not optional; they map the ASPX
pages to the appropriate precompiled classes in the precompiled assemblies. If you remove the .compiled
file, the page that it maps will not execute and you'll get an ASP.NET error.
I already showed the directory-level compilation mode. One really annoying aspect of this mode is that it creates new IDs for all the files on each build. Notice that each assembly has a generated name. Whenever you recompile the site the names of the assemblies and support files change. In other words, you can't create a repeatable build. In practice, this means that to deploy to a Web site, you pretty much need to completely redeploy all files in the BIN
directory every time!
Directory-level compilation is just one of about twenty compilation combinations available. In another mode, the fixed names
mode, you can create assemblies with fixed names. This mode creates a separate assembly for each page/control. Here's the command line to use fixed names mode.
aspnet_compiler.exe -f -fixednames -v
In this mode there's one assembly and one .compiled
file for each page and control. App_Code
is still compiled into a single assembly as is each theme. The one advantage of this approach is that it produces a repeatable installbut the file names still have a randomly generated hashcode at the end. However, this mode makes it possible to update just pages or controls that have changed, unlike directory-level compilation where every single compiled file and its associated .compiled
file must be updated. But fixed names mode also generates a lot of assemblies. Copying these assemblies to a live server will cause your online application to become unstable (and likely fail) as the files are updated one at a time.
If you're thinking: Yuck, that's a lot of files, I agree! Neither of these two approaches offers a really clean deployment scenario because you have to copy a lot of files. Compared to ASP.NET 1.x's CodeBehind deployment scenario, ASP.NET 2.0's deployment modes can be a nightmare.
To avoid this unstable site situation, you can copy a special marker fileApp_Offline.htm
to the root of the Web site to which you're deploying. When present, this page gets displayed whenever any request hits the ASP.NET pipeline. This is a pretty clumsy mechanism that requires file access to the server, but it's better than the alternative of crashing your Web site while the files are being copied to the server.
Yet one more option is partial compilation, which compiles only the CodeBeside classes but leaves the ASPX
pages to compile at run time on the server. The ASP.NET Compiler calls this an Updateable site
, but this is only partially correct. You still have to run the ASPNET_COMPILER
but include the -u flag to make the site updateable.
aspnet_compiler.exe -f -fixednames -u -v
When compiled with the -u
option, the ASPX
pages remain intact. In turn you will no longer need the .compiled
files because ASP.NET can parse the ASPX
pages to figure out what classes and dependencies are required to execute to the page. So the BIN
directory looks a bit cleaner with this approach.
However, now you need to make sure to deploy your ASPX
pages and keep them in sync with the server. It's important to understand that although you can edit the ASPX
pages on the server, the pages have been modified from your original development pages.
<%@ page language="C#" autoeventwireup="true"
inherits="DataEntry, App_Web_9kasz7w7" %>
Note that the Inherits tag includes the dynamically generated assembly name. This means that you can modify the page on the server directly, but it also means that you can't simply make a change to the page in Visual Studio and directly upload your page back to the server because it will not have the dynamic assembly name. Unless you use fixed names compilation, the assembly name will change on every build so you still have to update the page along with the assemblies if you use the default directory-level compilation.
You need to decide whether this mode makes senseit's really hard to keep changes in sync between development and live sites in this scenario because your development files and the server files are not compatible without a full recompile.
All these options can be very confusing and it's not easy to see which might work best for your scenario. To figure the compilation process option out, I built a small ASP.NET Compiler Utility that provides a graphical front end to the ASP.NET compiler for the most common options. The utility, shown in Figure 7
, lets you play with the various compiler combinations and quickly see the results in the output folder. It can also generate a batch file for you and lets you jump directly to your FTP client to upload the code to the server. It also works with Web Deployment Projects for single assembly compilation, which you'll learn about in the next section.