September 2010

Volume 25 Number 09

App Migration - Migrate Your ASP.NET 1.1 Apps to Visual Studio 2010

By Jonathan Waldman | September 2010

If you’ve been working with ASP.NET for more than a few years, chances are you’ve written solutions using Visual Studio 2003 for the Microsoft .NET Framework 1.1. In more recent years, newer, feature-rich .NET Framework 2.0, 3.0 and 3.5 versions have debuted—and you may have wondered whether it would be worthwhile or feasible to upgrade your trusty 1.1-Framework apps to one of them.

Today, as the new .NET Framework 4 is being embraced by developers around the globe, you might feel more compelled than ever to seriously consider a migration effort. If you decide to do so, rest assured that Microsoft has provided useful tools to facilitate such an undertaking, resulting in modernized ASP.NET apps that can take advantage of the latest .NET Framework innovations. Specifically, I’ll show you how to reinvigorate ASP.NET 1.1 solutions by migrating them to Visual Studio 2010 (Professional, Premium or Ultimate)—enabling them to target the .NET Framework 2.0, 3.0, 3.5 or 4 versions.

Why Migrate?

Even if your goal is to simply maintain your existing ASP.NET 1.1 sites, your support and extensibility options are dwindling. As a 1.1 developer, you should be concerned that Microsoft retired Mainstream Support for Visual Studio 2003 on Oct. 14, 2008—and has stated that it will issue no further service packs for Visual Studio 2003 or for the .NET Framework 1.1. (Microsoft will, however, offer Extended Support for Visual Studio 2003 until Oct. 8, 2013.)

You should be downright alarmed, however, that a growing number of third-party vendors have ceased offering or supporting components that can run against the .NET Framework 1.1 or that extend the Visual Studio 2003 IDE. Indeed, your .NET Framework 1.1 Web apps and the Visual Studio 2003 IDE are being alienated and are being eased into oblivion.

 Yet other reasons abound. There have been so many enhancements to the .NET Framework, the C# and Visual Basic .NET programming languages, and to the Visual Studio IDE that migrating your .NET 1.1 sites to .NET 2.0 or beyond (hereafter referred to as 2.0+) would finally enable you to enhance them using the latest tools and technologies, as well as all the modern language and framework features (such as master pages, AJAX, Windows Communication Foundation [WCF], Silverlight, LINQ, partial classes, generics, lambda expressions and anonymous methods) already embraced by leading .NET developers. In general, the higher the framework version you choose your ASP.NET app to target, the greater potential and power you will have at your fingertips. You would also find solid support not only from Microsoft itself (as of this writing, Microsoft offers Mainstream Support for all 2.0+ framework versions), but also within active developer forums and by third-party tool vendors. There are also widely available books covering all aspects of the latest technologies—and many sites offering video-based courses, blogs, white papers and other training options.

 The latest, state-of-the-art Visual Studio 2010 IDE is almost itself a justification for migration. It’s generations ahead of the Visual Studio 2003 IDE, supports new features such as IntelliTrace and can be extended using a variety of powerful third-party plug-ins that virtually guarantee new levels of programming productivity. While some rare users will need to continue using older versions of Visual Studio for various reasons, Visual Studio 2010 makes running side-by-side installations of Visual Studio 2005 and Visual Studio 2008 virtually unnecessary because Visual Studio 2010 can target the 2.0+ frameworks. Yet, like Visual Studio
2005 and Visual Studio 2008, Visual Studio 2010 can’t target the 1.1 framework. This means you either have to continue to run Visual Studio 2003 or you have to migrate your ASP.NET 1.1 project to a newer framework.

Finally, developers with 1.1-framework-only experience simply aren’t as marketable as those with 2.0+ framework experience. Competition for developer positions is high, so you want to give yourself every possible edge; leveraging newer framework features in your code will enhance your candidacy and credibility as a professional software developer.

Migration Issues

So why hasn’t everyone already migrated up from ASP.NET 1.1 during any one of the major Visual Studio and .NET Framework releases since Visual Studio 2003? One reason is that developers would need to implement the ASP.NET 1.1-to-ASP.NET 2.0 migration option Visual Studio 2005 offered. That doesn’t sound so bad, but realize that when Visual Studio 2005 was first rolled out, it required that an ASP.NET 1.1 project be converted to a newfangled Web-project type. This meant that the very architecture on which an ASP.NET 1.1 site was built had to be painstakingly reworked and rigorously regression-tested. Many developers considered this process tantamount to rewriting the site from scratch, presenting a cost and technical challenge deemed insurmountable. As a result, decision makers often left ASP.NET 1.1 sites as they were.

To better appreciate this ASP.NET 1.1-to-ASP.NET 2.0 migration challenge, it’s important to understand that all ASP.NET 1.1 Web projects are organized using a file-folder configuration that is project-driven. This project type was originally dubbed the “2003 Web project model” and is now known as a Web Application Project (WAP). When Visual Studio 2005 was released, Microsoft introduced a new folder-driven project type that was designed for the .NET Framework 2.0. This project type was originally dubbed the “2005 Web project model” and is now known as a Web Site Project (WSP). (Confused? Use the simple trick of remembering the acronyms in their alphabetical order: WAP comes before WSP just as Visual Studio 2003 comes before Visual Studio 2005.)

While an in-depth discussion of WAPs and WSPs is out of scope here, suffice it to say that Microsoft originally intended all migrated 1.1 Web applications to become WSPs via its included Conversion Wizard. Concerned developers immediately protested because the original WAP project type offered specific technical and performance advantages absent in the newer WSP project type. An ASP.NET development community furor quickly ensued as developers, managers and stakeholders learned that Microsoft had provided only an ASP.NET 1.1 WAP-to-ASP.NET 2.0 WSP migration option—and that this proved to be time-consuming and costly, especially for sites of any complexity. Detailing the technical issues that arise during such a migration would constitute a separate multi-part article; you can learn more by reading the MSDN library article, “Common Web Project Conversion Issues and Solutions” (

Fortunately, Microsoft responded quickly and soon offered a revised Conversion Wizard in Visual Studio 2005 SP1. This time, the Conversion Wizard would convert an ASP.NET 1.1 WAP to an ASP.NET 2.0 WAP. Yet many developers missed learning about this migration option and thus never explored it. In Visual Studio 2010, the Conversion Wizard converts an ASP.NET 1.1 WAP to an ASP.NET 2.0+ WAP (2.0+ refers to the fact that, once converted, you can target 2.0, 3.0, 3.5 or 4), still providing an opportunity to migrate older Web apps. (You can’t convert an ASP.NET 1.1 app to a WSP app—nor would you likely want to—using the Visual Studio 2010 Conversion Wizard; you would need to have access to the Conversion Wizard provided in the original Visual Studio 2005 that was released before SP1.)

It might interest you to know that whenever you start a new project in Visual Studio 2010, you can choose whether you want to create a WAP or a WSP. Microsoft has promised to offer WAP and WSP support in current and all future .NET Framework releases.

The Process

Migrating your ASP.NET 1.1 apps using Visual Studio 2010 consists of the following broad steps (I’ll discuss each in detail):

  • Run the Conversion Wizard.
  • Set the target framework and startup page.
  • Compile and fix.
  • Convert pages and user controls to partial classes.
  • Compile and fix.

Run the Conversion Wizard To use the Conversion Wizard for a 1.1 WAP-to-2.0+ WAP conversion (our goal), you must install the Visual Web Developer option during the Visual Studio 2010 setup. If you didn’t, you need to add it by re-running Visual Studio 2010 Setup and using its Change or Remove Microsoft Visual Studio 2010 option; then choose Add or Remove Features; then ensure that the Visual Web Developer feature is checked (see Figure 1).

image: Ensure the Visual Web Developer Component Is Installed Before Launching the Conversion Wizard

Figure 1 Ensure the Visual Web Developer Component Is Installed Before Launching the Conversion Wizard

If Visual Web Developer isn’t installed, the Conversion Wizard still launches and runs. It will be able to convert all projects in your solution except for your Web project. It will advise you that you need to install Visual Web Developer in order to convert your Web project.

Before you undertake a conversion effort, it just makes good sense to ensure that your application not only builds and runs, but also that it’s as clean and organized as possible. Therefore:

  1. Clean your application by removing any unused or unneeded files, thereby reducing your Web application to its essential components.
  2. Ensure every project in your solution compiles with no compile-time errors.
  3. While I recommend adding your solution to source control if it isn’t already so configured, do verify that no files are checked out exclusively from the repository. Having your solution under source control will let you examine specific changes made by the wizard after the conversion process has completed.
  4. Ensure that no files or folders outside of source control are marked as read-only. This lets the wizard update those files/folders as needed.
  5. Create a backup. If you run your solution in a virtual machine, it’s best to simply back up the entire virtual machine (or create a snapshot of it). Otherwise, back up your entire application—including all dependencies. If you’re not sure about the dependencies, a good place to look is in your application’s solution (.sln) file as well as in the individual project (.proj) files (these are text files that can be visually inspected). Many ASP.NET solutions contain projects that point to network locations or to folders outside the Web root or application folders. Not backing up these dependencies can cause you tremendous grief should you wish to restore your application from the backup files. Keep in mind that the full migration process makes changes to every project in your application, so it’s advantageous to understand your application’s dependencies before getting started. In addition, if you’re using projects that are shared among several ASP.NET 1.1 applications, realize that once these solutions have been migrated, they can no longer be opened in Visual Studio 2003. If you work in a team environment, making changes to shared projects will also affect team members’ solutions, which could end up referencing converted projects. Thus, whether shared across projects or teams, you should decouple shared projects by making copies of them and ensuring that a local copy exists on your development workstation. Your solution file will change if you move a project (in order to decouple it, for example), so you might want to think about backing up the solution file before making changes to any of the projects it references—and then back up again after the project dependencies have been properly decoupled but before running the Conversion Wizard. Finally, you may discover errors in your original solution files after the conversion process completes; having a handy backup of your pre-converted solution will make it easy for you to go back and fix those errors before re-running the Conversion Wizard.
  6. Consider setting up a parallel environment: Visual Studio 2003 and Visual Studio 2010 can run side-by-side on the same machine, so you can run your ASP.NET 1.1 site alongside your ASP.NET 2.0+ site. This will facilitate your QA-testing efforts post-migration.

To launch the wizard, open your Visual Studio 2003 solution file using the File, Open, Project/Solution menu option in Visual Studio 2010. You will soon see the Visual Studio Conversion Wizard introductory dialog (see Figure 2). Click Next.

image: The Visual Studio Conversion Wizard Introductory Dialog

Figure 2 The Visual Studio Conversion Wizard Introductory Dialog

The Conversion Wizard may identify issues while it processes and you may find yourself wanting to restore your solution from a backup, make a few changes and start the process again from scratch. This step makes it a snap to create a backup (see Figure 3) even though it places all of your solution’s dependencies within the backup folder you specify, which means that to restore properly, you have to be absolutely certain you know the original arrangement of those backed-up folders.

image: The Conversion Wizard Gives You an Opportunity to Create a Backup Before Proceeding

Figure 3 The Conversion Wizard Gives You an Opportunity to Create a Backup Before Proceeding

Given that, to back up your solution at this step, simply supply a folder path and the wizard will create a child folder called Backup into which it will place the solution’s files. Every project in the solution will be backed up to a corresponding subfolder under the Backup folder—even if it originates outside the original solution’s root—so for the backup to be successful, it’s important to ensure that project names are unique across your solution. Click Next.

You will now see a final dialog box containing an advisory regarding source control and read/write permissions (see Figure 4).

image: The Conversion Wizard Advises You Before Letting You Continue

Figure 4 The Conversion Wizard Advises You Before Letting You Continue

If you chose to do a backup, you will see the type of backup you requested and to what location the backup files will be written. You will see a summary of the solution name being converted along with all of its projects. If everything looks accurate and acceptable, click Finish.

Now you may be prompted for logon credentials for your source control repository (such as Visual SourceSafe) so that your project can be checked out.

You will now see a progress bar as each of your solution’s projects is converted. The process may take several minutes as the wizard iterates across the projects in your solution.

The Conversion Wizard displays a message explaining that you’ve completed the first step and that your Web application now needs to be converted (see Figure 5).

image: The Conversion Wizard Lets You Know that You Will Need to Convert Your Web Project in Order to Complete the Migration

Figure 5 The Conversion Wizard Lets You Know that You Will Need to Convert Your Web Project in Order to Complete the Migration

It then alerts you that it has completed its initial process (see Figure 6).

image: The Conversion Wizard Alerts You When the Conversion Is Complete

Figure 6 The Conversion Wizard Alerts You When the Conversion Is Complete

You can then review the conversion log using the Conversion Report template. This file, called Upgrade­Log.XML, is placed in the same folder as your solution’s .sln file. The upgrade log shows which project files were converted and displays any relevant errors and warning messages. It also provides useful comments as well as comments regarding the framework version that each project targets. I have included an excerpt from this report in Figure 7.

image: The Conversion Log Shows Details About the Converted Web Application

Figure 7 The Conversion Log Shows Details About the Converted Web Application

All warnings and errors should be reviewed. Warnings (such as a change to the relative path of a backup path) generally concern minor technical concerns that don’t typically require further action in order for you to be able to successfully compile your converted solution. However, error messages (such as a missing file reference) need to be carefully reviewed and acted upon because they generally involve issues that will prevent you from being able to successfully compile your converted solution. If you have many errors, the Conversion Log does a good job articulating the kind of action you need to take, and you can usually find plenty of additional help using the Visual Studio 2010 help files or at various technical Web sites. In some cases, you may find it best to take note of the Conversion Log errors and address them in your original Visual Studio 2003 project files rather than in the converted solution (this is where the backup you made comes in handy). You can always re-run the Conversion Wizard against your modified Visual Studio 2003 solution.

Once you’ve reviewed all warnings and have resolved all errors, you can dismiss the Conversion Wizard’s final screens. The Conversion Wizard has now completed its tasks. Your solution (.sln) file and its project (.proj) files are now in the Visual Studio 2010 format. However, you still have some work ahead to complete the migration.

Set the Target Framework and Startup Page When the Conversion Wizard finishes, it will have configured your Visual Studio 2003 Web project to run against the .NET Framework 4 while setting your solution’s other projects to run against the .NET Framework 2.0. While it’s acceptable to mix-and-match framework versions, I recommend using a single framework target across all of your solution’s projects unless you have restrictions imposed on by your Web-hosting company or organization infrastructure. (Visual Studio 2010 modifies its IDE feature set depending on the target framework in effect for the active project. If your projects target different framework versions, you may find the IDE’s behavior puzzling as you switch among projects. Having all projects at the same framework version lets the IDE present a consistent interface across all of your projects and also lets you program against a consistent framework.)

If you wish to change the target framework for any of your converted projects, simply right-click the project root in Solution Explorer and select Properties. In the configuration page that appears (see Figure 8), select the Application tab and change the Target Framework to any of the 2.0+ framework values.

image: Change the Target Framework for Any Project to 2.0, 3.0, 3.5 or 4

Figure 8 Change the Target Framework for Any Project to 2.0, 3.0, 3.5 or 4

Finally, set the start page for your Web project. To do this, find the page in Solution Explorer, right-click it, and choose the Set as Start Page option.

Compile and Fix Now that the solution and project files have been upgraded to the Visual Studio 2010 format, your ASP.NET 2.0+ WAP is ready to be compiled. In order to force-build all projects in your solution, I recommend compiling within Visual Studio 2010 using the Build, Rebuild Solution menu option. After rebuilding, you can view any build issues by displaying the Error List window (you can display this by selecting the View menu and the Error List option). The Error List window displays errors, warnings and messages (you can specify which of these you see in the window by toggling the corresponding Errors, Warnings and Messages buttons). Visual Studio 2010 usually provides clear guidance on how to resolve the items in the Error List window. If you don’t understand the error/warning/message text, simply select the Error List window line containing the advisory and hit <F1>. A help window will appear containing more detailed information about the issue (if you didn’t install local help, you can connect to the Internet to view it). Yet most of the errors you see will concern changes to the framework that cause naming conflicts with your own code. You can usually resolve those by fully qualifying your references with a namespace. And most of the warnings you see will concern obsolete members. While you can still use obsolete members, you should know that they likely won’t be supported in the next-higher version of the .NET Framework. If you see obsolete members and you’re targeting the 2.0 framework, you will likely not be able to use that member when you decide to target a 3.x or the 4 framework.

Be prepared to spend some time resolving these Error List window issues. You should be able to resolve all errors and most, if not all, warnings before moving on to the next steps.

Convert Pages and User Controls to Partial Classes The next step involves running a Convert to Web Application (hereafter, CWA) command. Although you can run this command against an individual page or user control to get a feel for the
kind of changes it makes, it’s quicker to run it against the entire solution. To do this, right-click the Solution node in Solution Explorer and choose Convert to Web Application. This process does the following:

  1. Implements partial classes by adding a new “designer” document for pages and user control.
  2. Sets AutoEventWireup for pages and user control.
  3. Adds declarative event handlers for each control on pages and user controls.

ASP.NET 1.1 applications have code-behind modules (aspx.cs and ascx.cs for C# and aspx.vb and ascx.vb for Visual Basic .NET) containing both developer-authored and Web-form designer-generated code. When you create pages or user controls in Visual Studio 2003 and add controls to them using the Web form designer, the IDE adds protected instance fields to your code-behind modules so you can refer to those added controls. After running the CWA command, a designer document appears for each page and user control (the Solution Explorer shows this file only when its Show All Files option has been enabled). You will observe that designer file names are the same as the page or user control along with a designer.cs (C#) or designer.vb (Visual Basic .NET) extension.

For example, if you have a page called MyPage.aspx in C#, there will be a new document called MyPage.aspx.designer.cs. This designer document contains protected instance fields that used to be in your code-behind module. Those fields have shifted to the designer module and thus are no longer mixed in with your own code. This is possible because designer modules are partial classes, which means that the CWA command also turns the code-behind code for the corresponding page or user control into a partial class.

For example, instance fields in C# and Visual Basic .NET appear as follows in the code-behind documents of Visual Studio 2003 projects:

Protected WithEvents MyButton As System.Web.UI.WebControls.Button
protected System.Web.UI.WebControls.Button MyButton;
The CWA command moves each to a corresponding designer file:
Protected WithEvents MyButton As Global.System.Web.UI.WebControls.Button
protected global::System.Web.UI.WebControls.Button MyButton;

(global:: indicates that the namespace search for System should begin at the global namespace level and thus assures that the framework System namespace won’t be hidden by your own System namespace.)

The creation of the designer file is dynamic and can be regenerated at any time. Thus, you can safely delete your designer.cs or designer.vb document and regenerate it (or restore it if it’s missing) simply by right-clicking the page or user-control node in Solution Explorer and re-running the CWA command against it. The CWA command scans for server controls in the HTML markup for a page or user control and generates the necessary instance variables in the designer partial-class file. It then removes any instance variables that still appear in your own code-behind file (aspx.cs, ascx.cs, aspx.vb or ascx.vb).

Partial classes allow the source code for a single class, struct or interface to be written across two or more physical files within a namespace. The compiler later unites these partial definitions to form a single declaration for each type. While partial classes remain the de facto mechanism used by Visual Studio to cleanly separate developer-authored code from IDE-generated code, developers also leverage them in code-behind modules—especially when working in a team environment.

Because partial classes are the norm for ASP.NET 2.0+ applications, you should break up your ASP.NET 1.1 classes into partial classes. If you skip this step, your pages and user controls will continue to function but you will need to manually update control field declarations in the code-behind files when you modify the controls on a page (.aspx) or user control (.ascx).

The CWA command also changes the value of AutoEvent­Wireup as well as the way events are declared and wired up, and I think the impact of this is important enough to discuss in detail. AutoEventWireup is a Boolean attribute that specifies whether Page-object event handlers are wired up implicitly (when True) or explicitly (when False). For pages, AutoEventWireup is set in the @Page tag; for user controls, AutoEventWireup is set in the @Control tag. The CWA command sets AutoEventWireup to True for C# pages and user controls, and sets it to False for Visual Basic .NET pages and user controls.

Developers have different preferences, and it’s quite possible that some pages or user controls in your ASP.NET 1.1 application set AutoEventWireup to True or False—or don’t specify it at all, in which case its default comes from web.config or, if not specified there, from machine.config. It’s important to know that the value of AutoEventWireup can change after running the CWA command. This change can cause unanticipated behavior—such as page events firing twice. This most often occurs when you created your own naming convention for Page-object events in your ASP.NET 1.1 application. For example, consider this C# code in which a Page_Load2 handler is wired up to the Page.Load event delegate:

this.Load += new System.EventHandler(this.Page_Load2);

When AutoEventWireup is False, the event will fire once, as expected—even if there is a code-behind function called Page_Load. However, when AutoEventWireup is True, both events fire—once for the explicit wire-up code shown here, and once for the implicit wire-up code that subscribes the Page_Load event handler to the Page.Load event. Consider the code in Figure 9.

Figure 9 Testing AutoEventWireup Behavior

public partial class _Default : System.Web.UI.Page
  override protected void OnInit(EventArgs e)
  private void InitializeComponent()
    this.Load += new System.EventHandler(this.Page_Load2);
  protected void Page_Load()
    Response.Write("In Page_Load().<br />");
  protected void Page_Load2(object sender, EventArgs e)
    Response.Write("In Page_Load2().<br />");

The code in Figure 9 generates this output:

In Page_Load().
In Page_Load2().
Top of Form 1
Bottom of Form 1

The same thing happens in Visual Basic .NET when AutoEventWireup is set to True. Consider the following code:

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
  Response.Write("In Page_Load.<br />")
End Sub
Private Sub Page_Load2(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles MyBase.Load
  Response.Write("In Page_Load2.<br />")
End Sub

When AutoEventWireup is True, both event handlers fire, causing the page to display:

In Page_Load2.
  In Page_Load.

You can see that not only do two event handlers execute, but also the order in which they execute—as with all multicast delegates—might not be what you expect. Finally, realize that when AutoEventWireup is True, page event handlers with the proper function name, such as Page_Load, will fire whether they’re defined with or without arguments. For example:

protected void Page_Load()
    Response.Write("In Page_Load().<br />");

is the same as:

protected void Page_Load(object sender, EventArgs e)
    Response.Write("In Page_Load().<br />");

If both are present, only the one with arguments fires—another issue to consider when troubleshooting. Thus, in general, be careful testing pages and user controls, especially when the AutoEvent­Wireup setting was changed by the CWA command.

Finally, the CWA command removes explicit C# and Visual Basic .NET code that wires up control events and instead uses declarative event attributes in the page’s or user control’s markup. For example, in ASP.NET 1.1, a click event on a button would typically have an event handler in code-behind, such as:

this.MyButton.Click += new System.EventHandler(this.MyButton_Click);

The CWA command removes this and instead adds an OnClick attribute to the server-control declaration as follows:

<asp:Button ID="MyButton" runat="server" Text="MyButton" onclick="MyButton" />

In Visual Basic .NET, declarative events aren't added. Instead, the Handles keyword is added to the code-behind. Th us, the markup for a Button control will appear as:

<asp:Button ID="MyButton" runat="server" Text="Button" />

while the code-behind wires up the control to the handler:

Protected Sub MyButton_Click(
  ByVal sender As Object, ByVal e As EventArgs) _
Handles MyButton.Click
End Sub

Event delegates for these declarative event-handler constructs are created at compile time.

Compile and Fix The migration is now complete. I recommend that you rebuild your solution and go through the exercise of addressing any remaining compiler errors or warnings you may receive. Note that you need to resolve compilation errors before you can successfully build your Web project and before you can view your migrated Web site in a browser. You should also address compilation warnings, but they aren’t considered critical and won’t prevent you from using your Web application. Finally, take note of all compiler messages because they generally provide helpful recommendations for improvements you should consider implementing when time allows. Beyond errors and warnings, it’s important to regression test and QA test your migrated code, and be especially careful to ensure that events fire as expected.

Post-Migration Considerations

Because your ASP.NET project now targets a newer framework and is running under a more modern version of the IDE, you should be aware of a few additional issues.

If you migrated your ASP.NET 1.1 solution from a 32-bit OS to a 64-bit OS, you should realize that IIS 6.0 and later support both 32-bit and 64-bit operating modes. Because ASP.NET 1.1 runs only in 32-bit mode, you may find that your converted ASP.NET app still has 32-bit dependencies (such as COM or P/Invoke calls) which may not continue to function properly post-migration. To fix this, access the Advanced Settings of your application’s Application Pool and set the Enable 32-bit Applications value to True.

Visual Studio 2010 expects Web pages to be XHTML-compliant. Your pages from ASP.NET 1.1 likely are not. Most pages will therefore show XHTML validation warnings (to see these, view your page in Source or Design mode, then access the View menu and select Error List). While these warnings won’t prevent a page from running, they indicate that the pages may not render properly in modern browsers. As time permits, you should update your pages and user controls so they’re XHTML-compliant, which will ensure that they render properly in modern browsers. If your Web app specifically targets an older browser—or you don’t want to be bothered with markup validation errors at this time—you can change how markup is validated by going to the Tools menu, choosing Options and going to the Text Editor node, then changing Target to Internet Explorer 6 (see Figure 10). This approach is suitable only for developers who are required to target Internet Explorer 6, as might be the case if your app is a corporate intranet app, for example. This effectively sets rendering validation to a level similar to the one you likely used in Visual Studio 2003.

image: You Can Suppress XHTML Validation Errors by Changing the HTML Validation Target to Internet Explorer 6

Figure 10 You Can Suppress XHTML Validation Errors by Changing the HTML Validation Target to Internet Explorer 6

For those apps that will need to display properly in browsers other than Internet Explorer or in versions of Internet Explorer beyond version 6, you should continue to show XHTML markup errors in the HTML editor and you should make use of the new .NET Framework 4 controlRenderingCompatibilityVersion configuration setting, available as a property in the Web.config system.web section:

  <pages controlRenderingCompatibilityVersion="4.0"/>

If controlRenderingCompatibilityVersion isn’t set in Web.config, it defaults to the running version of ASP.NET. When you specify the controlRenderingCompatibilityVersion value, however, you can set it to either “3.5” or “4.0” (the conversion wizard sets it to “3.5,” which renders pages the same way as in ASP.NET 3.5). This setting determines how markup specified in your .aspx files is ultimately rendered to the browser. To cite an example from the Visual Studio 2010 online help, when controlRenderingCompatibilityVersion is set to “3.5,” a server-side ASP.NET Label control with its IsEnabled property set to false will render an HTML span element with its “disabled” attribute set to “disabled”; when controlRenderingCompatibilityVersion is set to “4.0,” the resulting span element will instead include a “class” attribute with a reference to a CSS class.

You should be aware that using the “4.0” setting generates modern XHTML markup—and this can break client script or CSS rules that worked properly in the ASP.NET 1.1 version of the page, thereby affecting the behavior and/or aesthetics of the rendered content. Thus, until you are fully committed to generating valid XHTML, I suggest that you set controlRenderingCompatibilityVersion to “3.5.” And if you use this “3.5” setting, you need to know about xhtmlConformance (which applies only if controlRenderingCompatibilityVersion is set to “3.5”), which can be set to “Legacy,” “Strict” or “Transitional” (the default value). “Strict” renders XHTML 1.0 Strict markup; “Transitional” renders XHTML 1.0 Transitional markup; “Legacy” renders HTML similar (but not necessarily exactly) to the way it was rendered in ASP.NET 1.1:

  <pages controlRenderingCompatibilityVersion="4.0"/>
  <xhtmlConformance mode="Transitional"/>

In my experience, you should avoid “Legacy” mode, as it can interfere with the proper functioning of the ASP.NET AJAX UpdatePanel. Also, note that the controlRenderingCompatibilityVersion value doesn’t change the DOCTYPE of your Web page—it simply changes the way ASP.NET controls render themselves. Thus, getting your pages to render properly is largely due to the combination of controlRenderingCompatibilityVersion, xhtmlConformance and DOCTYPE values as well as the target browser type and version used.

Another thing to consider: You may want to change the virtual directory under which your newly migrated site runs—especially if you plan to run it in parallel with the ASP.NET 1.1 version. To do this, right-click the Web project in Solution Explorer, choose Properties and then access the Web tab. Under Servers, you’ll see an option for Use Local IIS Web Server. Be sure that option is selected, specify a Project URL (such as https://localhost/mysitemigrated), and click the Create Virtual Directory button if the virtual directory doesn’t exist.

ASP.NET 1.1 applications use the Windows ASPNET user to assign privileges on files and folders under the virtual root. ASP.NET 2.0+ uses the NETWORK SERVICE user. If your application requires that ASP.NET have write access to certain files or folders, for example, it’s important to grant those rights to the NETWORK SERVICE user. If you’re ever unsure which user needs this access, you can view that user name by examining the value of the Envionment.UserName property while running an ASP.NET application.

If you use any third-party add-ons or dependencies (whether as binary or source), you will want to check with the vendor to ensure that you have the latest version. For example, the popular logging program, NLog, offers 1.1 and 2.0 library builds. Grab the 2.0 build and spare yourself the effort of migrating the 1.1 code yourself. Also, vendors will be providing updates to productivity add-ons designed for the Visual Studio IDE. Be sure to upgrade to obtain the most current versions of those products for your new Visual Studio 2010 IDE.

After migrating your ASP.NET 1.1 Web apps, you’ll realize two immediate benefits. First, you’ll no longer require Front Page Server Extensions (FPSE) to power your site (unless you optionally wish to continue using it). Second, you’ll no longer need to have IIS installed on your development machine because Visual Studio 2010 offers its own built-in ASP.NET Development Server. And while you can continue to run Visual Studio 2003 ASP.NET applications side-by-side with Visual Studio 2010 ASP.NET applications (for QA/debugging purposes, for example), your converted Visual Studio 2010 ASP.NET application will no longer require Visual Studio 2003 or access to the .NET Framework 1.1.

 If you’re a C# developer, you may notice that page and user-control events no longer appear in the Properties window as a yellow thunderbolt icon when viewing them in design mode. To view/create these events as in Visual Studio 2003, you will need to right-click the page (.aspx) or user control (.ascx) in the Solution Explorer and choose View Component Designer. At that point, you’ll see a Properties window that contains the familiar list of events. You can double-click any of the events in the list to create your event procedure and delegate wire-up code (this gets added to the InitializeComponent function).

When it’s time to host your site, you need to know which CLR is required. When you use the 3.0 and 3.5 .NET Frameworks, you’re running against the CLR 2.0; when you use the .NET Framework 4, you’re running against the CLR 4.0. Your hosting company must support the CLR 4.0 in order to host your ASP.NET 4.0 solution.

I hope I’ve helped you transition your Visual Studio 2003 ASP.NET apps to Visual Studio 2010. Once you do so, you’ll have a whole new world of programming technologies at your disposal. I believe it’s a relatively painless technology decision you’ll never regret making.

Jonathan Waldman has written for PC Magazine and is a senior Microsoft Certified Professional who leverages .NET Framework technologies to passionately create customized software solutions for the desktop and the Web. He may be reached at

Thanks to the following technical expert for reviewing this article: Scott Hanselman