Back to article

Working Smarter With ASP.NET 2.0

April 25, 2006

One of the interesting things about ASP.NET is that it's such a huge and flexible development system that every team finds their own way of working with it. Microsoft has their recommended approaches, but they've enabled plenty of alternative ways of skinning a Web site. Recently I was in a position of helping a somewhat resource-constrained team get a fairly substantial site up and running with ASP.NET 2.0, and I thought it might be worth sharing some of the things we did on the way to a successful launch. Perhaps these ideas - some mainstream, some wild - will give you some notions for your own online development.

Start With a Known Quantity

As you may already know, ASP.NET 2.0 introduces a new way to think about organizing the files for your Web site. While the new Web Site Projects do offer advantages for some situations, they can be problematic to manage from a source-code control perspective. More importantly, they can represent a substantial learning curve for developers steeped in the "old" way of doing things. Fortunately, if you don't want to go up that learning curve right now (and with a mix of old a new code to support, we wanted to avoid the curve as long as possible), there's an alternative: Visual Studio Web Application Projects.

Web Application Projects allow you to use the Visual Studio .NET 2003 Web project model with Visual Studio 2005. They're supported by Microsoft, and at the moment the necessary bits are at the RC1 stage. Our team found them to be quite stable, and the familiarity of the project model more than made up for the few minor bugs we hit. If you're happy with the VS .NET 2003 way of creating Web applications, you should definitely check this add-in out.

Lightweight Deployment

One of the earliest (and perhaps most unusual) decisions we made was to combine our deployment process with our source code control process. We use Subversion for version control in this particular team. Rather than adopt another tool for deployment, we simply installed a Subversion client on the Web server itself. This made deployment a matter of running svn update on the server to pull down the most recent copy of the files for the site. This isn't a completely ideal solution (it does put some extra files on the Web server), but it's quick and easy.

Using this approach does require some discipline and coordination between developers and whoever updates the Web server. I'm a strong advocate of not checking broken code into the source code repository, but that becomes even more critical when there's a chance of broken code being deployed where the customer can see it. In our case, we required testing before commits to the repository, and only the project manager updated the live copy on the Web site.

Managing the Environment

With the same codebase running on developer workstations and the live server, we were faced with another problem: how could we manage application settings that should be different between development and production boxes? For example, we didn't want our developers mucking about in the live database, nor did we want the live server using our test SMTP server to relay e-mails. The answer proved to be somewhere between "clever" and "disgusting hack," depending on your point of view, but in practice it's working quite well for us.

We keep a Globals object in our code to access various useful things, including this AppSettings method:

// Return an app setting from the web.config file
// uses key_PROD if file _prod exists & key exists
// else uses key_STAGE if file _stage exists & key exists
// else uses key_MACHINENAME based on machine name if key exists
// else uses base key
public static string AppSettings(string SettingName)
    System.Configuration.Configuration config =
    string val;
    if (File.Exists(HttpContext.Current.Server.MapPath("~/_prod")))
            val = 
                config.AppSettings.Settings[SettingName + "_PROD"].Value;
            if (val != String.Empty)
                return val;
        catch (Exception ex) {}

    if (File.Exists(HttpContext.Current.Server.MapPath("~/_stage")))
            val = 
                config.AppSettings.Settings[SettingName + "_STAGE"].Value;
            if (val != String.Empty)
                return val;
        catch (Exception ex) {}

        val = config.AppSettings.Settings[SettingName + 
            "_" + System.Environment.MachineName].Value;
        if (val != String.Empty)
            return val;
    catch (Exception ex){}

    return config.AppSettings.Settings[SettingName].Value;

By using the Globals.AppSettings() method instead of calling the built-in AppSettings collection, we have the flexibility to use a single web.config file but still allow each developer to put their own settings in the file. We can also put in master overrides for staging and production servers without knowing the server names. For example, a small snippet of the web.config file might look like this:

<add key ="SMTPServer" value ="localhost"/>
<add key ="SMTPServer_MELVIN" value =""/>
<add key ="SMTPServer_PROD" value =""/>

Retrieving the value of Globals.AppSettings("SMTPServer") will return "" if the code is run on a machine named MELVIN, "" on any production server (production servers being identified by the presence of a zero-byte file named _prod in the application's root directory) and "localhost" on any other machine. A similar function sorts out multiple settings in the <connectionStrings> section of web.config the same way.

Conserving Developer Resources

One of our big problems was how to put together a comparatively large site without sufficient developer resources. On the other hand, we did have a dedicated project manager on the customer side, and some other resources who knew basic HTML but not ASP.NET. In designing the site, we did our best to leverage these other resources by making it possible to maintain whole pages outside of the Visual Studio environment using a simple HTML editor, or even Notepad. Within the application, we have various ASP.NET pages that look something like this:

<%@ Page Language="C#" MasterPageFile="~/Site.Master" 
 AutoEventWireup="true" CodeBehind="faq.aspx.cs" 
 Inherits="TheSite._faq" %>
<%@ MasterType TypeName="TheSite.Site" %>

<asp:content id="content1" contentplaceholderid="MainContent" 
  runat="server" >
    <div style="padding: 10px;">
      <asp:Literal ID="FAQLiteral" runat="server" 
        Text="FAQ here">

In the corresponding code-behind file there's a single method:

protected void Page_Load(object sender, EventArgs e)
    FAQLiteral.Text = File.ReadAllText(Server.MapPath("~/faq.html"));

The net result is that all the "meat" of this particular page comes out of a single HTML file that can be edited without all the ASP.NET scaffolding by pretty much anyone who understands the business requirements. We equipped the whole team, developers and non-developers alike, with TortoiseSVN, an Explorer-integrated Subversion client that makes version control almost trivially simple. With minimal training, the non-developers could supply content and leave our few high-end developers to code the tricky part of the site.

Design it Once With Master Pages

There are a whole bunch of new features in ASP.NET 2.0, and you have to balance off learning them against actually turning out billable work. One that proved to be a big win for us was the new master pages system, which allows you to divide a page into a region of stuff that doesn't change (like your site logo and menu) and a region of stuff that changes from page to page (the FAQ or product detail or whatever other content the page is concerned with.

Using master pages is pretty easy. The master page itself is a normal ASP.NET page:

<%@ Master Language="C#" AutoEventWireup="true" 
 Codebehind="Site.master.cs" Inherits="TheSite.Site" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
<html xmlns="">
<head id="Head1" runat="server">
    <title>Page title goes here</title>
    <form id="form1" runat="server">
         <table cellpadding="0" cellspacing="0">
                      <img src="~/images/header.gif" />
                      <asp:ContentPlaceHolder ID="MainContent" 

Of course, in a real site, your designers will make the master page much fancier than this bear-bones little example. The key difference between the master page and any other page is the presence of the ContentPlaceHolder control. This control (or controls - you can have more than one on a single master page) provides the rectangular region that will be filled with the content from individual pages. On each page, a Content control, whose contentplaceholderid property matches the ID property of the ContentPlaceHolder control, provides the bits to be poured into the blank. Look back at the FAQ page earlier in the article to see how the bits fit together.

Once you get the hang of it, master pages are easy to work with, and Visual Studio provides good design time support for them. In addition, you have full access to the properties of the master page from code in the individual content pages. For instance, you can write:

this.Master.Page.Title = "Frequently Asked Questions";

And yes, ASP.NET 2.0 does make it easy to set page titles (at last!).

Lessons Learned

I could go on, picking out other things we did in developing this particular site, but I'd like to end by stepping back and talking about overall development philosophy for a moment. It seems that just about every team these days is required to turn out more product with fewer resources than might have been thought reasonable a few years ago. Rapid development products like ASP.NET 2.0 and Visual Studio 2005 can help make up part of the deficit, but you also have to work smarter instead of harder to have any hope of delivering sufficient value to please your customers. Keep these key points in mind as you plan your technical strategy for any new project:

  • New product features are only worth learning if the time invested pays off in more functionality in the same time or the same functionality in less time. No customer ever cared that you used generics instead of collections just because they're more modern.
  • Use the whole team, not just developers. It doesn't make sense to make a few people the bottleneck.
  • A low tech solution that works is better than a fancy solution that you never quite get the bugs out of.
  • You're getting paid to build a site (or other product), not to prove how smart you are.

Remember, there are a lot of other teams out there who would be happy to do the same work you're doing, and probably at a lower price. Your job is to convince the customer that you're delivering the best bang for their bucks. Start there, not from the tools, and you'll be in good shape.

About the Author

Mike Gunderloy is the author of over 20 books and numerous articles on development topics, and the Senior Technology Partner for Adaptive Strategy, a Washington State consulting firm. When he's not writing code, Mike putters in the garden on his farm in eastern Washington state.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date