|s part of the Visual Studio® .NET Beta, the Visual Studio development team implemented a mechanism to receive feedback from beta test sites about product features and bugs. To accomplish this, the team added LAME button functionality to the development environment that allows users to easily report poorly worded error messages, awkward menu navigation—in short, any aspect of the product they consider lame or broken (see Figure 1). The development team also implemented a mechanism within the product to track how customers were using it. The log files generated allow the development team to further streamline the development to address actual customer usage needs. A Web site, http://beta.visualstudio.net, was created as the central location to gather this information, collect bug reports from users, and distribute updated information to the beta test sites.|
Figure 1 LAME Button
The original version of the beta Web site was developed using Visual Basic® 6.0 and ASP hosted on Microsoft Internet Information Services (IIS) 5.0. As the .NET products matured, the team wanted to gain experience using them in a real production environment, and migrating the beta Web site to Visual Studio .NET and the Microsoft .NET Framework was a perfect opportunity to do just that.
By experiencing the migration firsthand, the team was able to gain valuable insight into the product, provide real-world validation of the benefits of the .NET platform and Visual Studio .NET, and identify techniques developers could use in writing Visual Basic 6.0 and ASP applications today in preparation for Visual Studio .NET.
In this article, I'll take a look at some of the techniques used to migrate the Web site to the .NET platform, share some of the lessons learned, and offer some tips about things you can do today to make it easier to migrate your own applications to .NET.
The Original Site Design The tracking site is made up of three individual Web sites. At the publicly accessible Web site, beta test sites can log in, enter bug reports, upload log files, and view updated beta documentation and known issue lists. At the mirror Web site, Microsoft employees can gain access without going outside the corporate firewall. Finally, the administration site is used by beta program administrators to maintain the test site lists, manage the site content, and configure other aspects of the site.
Initially, the Web site was built using Visual Basic 6.0, ASP, Windows 2000, and SQL Server™ 7.0. At the time, Visual Studio .NET and the .NET Framework were about to be released as a Technology Preview, but were not mature enough to be used as the building blocks for this site. For that reason, the Web site was built using the existing Visual Studio and Windows 2000 technologies.
The Web site was architected in line with Windows DNA 2000 application design patterns. The customer UI was developed using Active Server Pages 3.0 and hosted in IIS 5.0. The application logic and data access code resided in an ActiveX® DLL written in Visual Basic 6.0 and registered in COM+ Component Services. The Visual Basic component used ActiveX Data Objects (ADO) to communicate with the SQL Server 7.0 database. Figure 2 shows the basic site architecture that was in place for the first release of the beta.visualstudio.net Web site.
Figure 2 The Beta Web Site Architecture
When the team considered migrating the existing site to Visual Studio .NET Beta 1, they decided to focus on the external customer Web site only (I'll explain why in the next section) and leave the administrative site alone. Migrating the external site would allow them to meet their goals of obtaining real-world experience and providing customers with a .NET reference implementation while implementing it all in a relatively short time frame (less than eight weeks).
Migration Options The first step of the migration process was to identify the options available for moving the customer portion of the site to Visual Basic .NET and the .NET Framework. Three potential approaches were identified:
Before starting any development work, the team identified a number of .NET features that could replace complex and, in some cases, troublesome code on the site and provide some new features. Specifically, they wanted to incorporate the following features into the site:
- Migrate the Web site and Visual Basic 6.0 components to ASP .NET and Visual Basic .NET.
- Migrate the Web site to ASP .NET and use COM+ interoperability to communicate with the existing Visual Basic 6.0 components.
- Leave the existing site untouched and extend the functionality of the customer Web site by adding new features to the site written in ASP .NET and Visual Basic .NET.
To take advantage of many of the features identified, the development team needed to migrate the ASP pages to ASP .NET. The changes did not require migrating the existing Visual Basic 6.0 ActiveX component. Instead the team enhanced the site by creating a new Visual Basic .NET component to implement the new Web Service and localization features.
- ASP .NET authentication to replace the custom security mechanism.
- ASP .NET Web Form validation controls to replace the client-side validation logic for bug reports and descriptions of lame features.
- ASP .NET Web Services to enable other Microsoft sites to integrate with the beta bug reporting mechanism.
- .NET Framework localization support to build a Web site that would be easy to localize.
- ASP .NET user controls to provide more dynamic and personalized menu and banner images on the site.
Now let's look at the specific changes that were made to the Web site application in order to implement this migration.
Incorporating ASP .NET Authentication The first step toward migration was to remove the custom security mechanism and replace it with the ASP .NET cookie-based authentication mechanism. Starting with the PDC Tech Preview and continuing with the Beta 1 release of Visual Studio .NET, the authentication goal of the Web site was to identify the people who were visiting the site—not to prevent people from visiting it. For that reason, a modified membership system was implemented that allowed visitors to register at the Web site and nominate themselves for future beta releases.
The purpose of identifying each visitor was to track the bug and LAME reports they entered and have the information necessary to follow up with those people. In addition to associating the feedback with specific beta sites, the site could be personalized to reflect the visitor's interests and draw their attention to additional information that pertained to their specific needs. Associating users with program areas of interest allows the site administrators to direct content to the beta sites most interested in it. The majority of the beta sites are interested in all aspects of Visual Studio .NET and the .NET Framework and have access to all content on the site, but beta sites interested in a specific aspect (Visual Studio .NET IDE shell integration, for example) are presented with a filtered view of the content tailored to their interests.
The original implementation of the authentication check used an ASP server-side include file and a method exposed by the Visual Basic component to verify the visitor-provided userid and password against the membership database. The include file provided reusable code to make the security check, but this also meant that the file needed to be included at the top of every page to ensure that the page wasn't exposed without authentication. Placing the include file on each page made it difficult for the administrators to configure pages that didn't require security because it required them to manually edit the page and remove the security include.
Authentication is easier in ASP .NET because cookie-based authentication allows a site's content to be secured by placing it within a specified subdirectory. When a user attempts to access the secured content, the .NET Framework determines if the user has been authenticated. If the user hasn't been authenticated, the .NET Framework redirects the unauthenticated request to a specified HTML form where the user enters his credentials and submits the form. If the application authenticates the user, the .NET Framework issues a cookie containing a key value that can be used to identify the user during future requests and redirects them to the originally requested page. The .NET Framework also provides a set of intrinsic classes for interacting with the authentication process and accessing the authentication information that's stored in the cookie.
The ASP .NET authentication mechanism is configured through the Web site's config.web file. This configuration file contains an authentication block that specifies the authentication mode, the URL for the HTML login form, and the password format. Figure 3 contains a sample config.web file that sets up cookie-based authentication.
The custom security implementation developed for the initial release of the Web site established a unique session ID for each visitor. Since a unique session ID for each visitor was already being generated, it was relatively straightforward to migrate the authentication process while leaving much of the existing code intact. ASP .NET authentication was set up to redirect unauthenticated users to the existing login page to submit their credentials. When the original login page is submitted, the userid and password are validated and a session ID is generated for the user.
Implementing ASP .NET authentication required only two changes to the original login page. Rather than writing the session key to a custom cookie, an ASP .NET authentication cookie was used, and set to a value equal to the session key. The users could then be redirected to the originally requested page via the RedirectFromLoginPage method of the CookieAuthentication class. On subsequent requests, the session ID is accessed via the .NET Framework's HttpContext.User class. Figure 4 contains the modified version of the login authentication check.
In addition to providing an authentication mechanism that is more secure and easier to maintain, ASP .NET authentication allows easy support for authenticated and unauthenticated content. Since security is determined by the directory structure specified in the config.web file, it can be changed by simply moving the content outside of the secured directory.
In order for the authentication mechanism to work, however, all content that required authentication (a vast majority of the public Web site) from .asp pages to .aspx pages (the ASP .NET file extension) needed to be changed. As you will see in the next section, this turned out to be a relatively straightforward process.
Migrating from ASP to ASP .NET In migrating the Web site, the team wanted to touch as little code as possible to reduce the likelihood of introducing bugs. In this section I'll take a look at what they referred to as the minimalist approach to migrating production ASP pages to ASP .NET. Using this approach, the goal wasn't to showcase new ASP .NET features, but to just get the site up and running under ASP .NET.
Most pages required three or four standard modifications to get them running. The most common change required removing the Set statement when assigning an object reference to a variable in ASP code. The .NET Framework and the underlying common language runtime (CLR) treat everything as an object, eliminating the need for the Set keyword. The following ASP code from the original site
was converted to:
'create the feedback object
set oFeedback = Server.CreateObject("BetaSiteMgr.Feedback")
The second modification was to explicitly specify an object's default properties when referenced in an ASP page. The CLR and ASP .NET removed support for parameter-free default properties. Unfortunately, even though explicitly specifying property values makes for more readable and maintainable code, many developers like to take advantage of default properties and save the typing. On the Web site, default properties were used most frequently when working with ADO recordsets. Sections of ASP code in the original site, such as this
'create the feedback object
oFeedback = Server.CreateObject("BetaSiteMgr.Feedback")
were converted in the following manner during the migration:
'set rs fields
rsLameError("BetaID") = Request.Form("betaid")
rsLameError("UserDescription") = Request.Form("bugDescription")
rsLameError("SeverityID") = Request.Form("severity")
The third modification was to change the way data type conversion functions were used. In ASP .NET, the VBScript data type conversion functions have been moved into the .NET Framework. This change required that ASP code such as the following
'set rs fields
be converted during the migration to look like this:
adoRS.fields("AreaID") = clng(oUploadManager.Form("cboArea"))
adoRS.fields("SubAreaID") = clng(oUploadManager.Form("cboSubArea"))
The final modification was to slightly alter calls to the Response.Write method to adhere to the ASP .NET method call format. In VBScript, procedures that do not return a value can be called without placing the procedure's parameters in parentheses. ASP .NET requires that parameters to all method calls, even those that don't return a value, be enclosed in parentheses. In the original site, it was common to find areas where the Response object's Write method was called without using parentheses. In order to convert the site to ASP .NET, it was necessary for the ASP code to be converted from the following
<% Response.Write "Thank You!" %>
After making these changes to the original ASP pages, the Web site was up and running under ASP .NET. This part of the migration took less than two weeks to complete. To identify all of the places where these changes were needed, the team created a new Visual Basic Web application in the Visual Studio .NET IDE, renamed the existing ASP pages using the .aspx extension, and added them to the project. Once the pages were in the IDE, Visual Studio .NET provided syntax highlighting and task list "to do" items, and compile-time errors became easy to track down.
<% Response.Write("Thank You!") %>
LAME Reports and the Validation Controls During the migration, the development team decided to modify the data entry pages to take advantage of the ASP .NET validation controls and remove some of the complexity in the existing code base. When users want to enter a LAME report, they are taken to a page from within the Visual Studio .NET IDE when they click either the LAME button on an error dialog, the Feedback link for a help document, or the Feedback (smiley face) toolbar button. In order to properly incorporate the validation controls into the LAME entry pages, it was necessary to rebuild those pages and make full use of the ASP .NET Web Form technology.
The Web Form validation controls provide a set of cross-browser validation functions without requiring you to write custom application script code. The validation controls support downlevel browsers (Microsoft Internet Explorer prior to version 4.0 and Netscape prior to version 5.0) by requiring a server round-trip to validate the control's value and report back the results. When an uplevel browser is detected (Internet Explorer 4.0 or higher and Netscape 5.0 or higher), a majority of the validation is performed on the client before sending the data to the server. In the case of uplevel browsers, the server-side validation is still performed when the page is posted to the server to prevent spoofing and bypassing of the validation rules.
The validation logic in the original LAME entry pages had a relatively simple purpose: to require that the user provide values for certain fields before submitting the form to the server. Despite the simple goal of the validation logic, it still required client-side script similar to the JScript® in Figure 5.
In addition to the client-side script validation, validation logic had to be provided on the server to prevent users from bypassing the client-side validation and submitting invalid data. With the ASP .NET validation controls, this logic was removed and replaced with Required, Compare, and RegularExpressionValidator controls. In addition to removing a majority of the JScript code from the page, the team took advantage of the RegularExpressionValidator control to enhance the validation. When an uplevel browser is detected, JScript is still sent down to the client so that validation can be performed prior to submitting the page to the server. The difference is that the team didn't have to develop the JScript code; the validation controls generated the appropriate code automatically.
Build version is a required field when entering a bug or general LAME report. In most situations, the user is presented with a dropdown list of valid builds from which to choose and the only validation required is that the user specifies a build (see Figure 6). In some instances however, like when the build version isn't listed, the user needs to enter the build version manually. The build version in this case can be specified in one of two formats, and the format can be validated before submitting to the server. The JScript to perform this validation would have been complex, but the RegularExpressionValidator control only requires that you define the proper regular expression rule to validate the entry. The following code contains the .aspx RegularExpressionValidator control code and property setting used to perform this check in the new page.
runat="server" display="dynamic" controlToValidate="txtBuild"
errorMessage="Also, please enter the Build Version in
the following format: NN.NN.NN.NNNN "
Bug Report Web Service The final aspect of the migration was to enhance the bug report entry capabilities and expose the bug report entry mechanism as a Web Service. To help get information about Visual Studio .NET and the .NET Framework out to the public, Microsoft built a number of additional sample and informational Web sites. These sites needed a mechanism by which customers could submit bug reports while on other Web sites and still have the information recorded in the bug repository. During the initial beta releases, sites also asked for an offline mechanism for reporting bugs that could then be sent to the Web site in a batch-oriented fashion. The obvious approach to satisfying all of these feature requests was to expose bug report entry as a Web Service.
A bug report entry requires a fair amount of additional data to be provided (operating system, language, product, area, and so forth) in order for the report to be easily categorized and brought to the attention of the appropriate development team. In order to allow alternate client applications to provide a rich and usable interface, it was necessary to make all of this information available to the client application. To reach the largest number of new client applications, the development team decided to use XML for transmitting this data.
To make the bug reporting service easier to use, they implemented multiple interfaces and methods for saving bug reports. One interface assumes that the client application is capable of providing the ID values associated with the additional bug report data that the user specified (OS, language, and so on). The alternate interface allows the client application to submit the additional data as string values that match the values presented in the bug reporting page at beta.visualstudio.net. If the client uses the string-based interface, the bug reporting service converts the string to its associated ID value and passes the information to the bug reporting business component to validate it and persist it to the database.
The original Visual Basic 6.0 bug report component used ADO recordsets to expose the data to the client application and receive the completed bug report from the client application. In order to expose this data as XML from the Web Service, one option was to use the ADO recordset's adPersistXML format to stream the recordset data into an XML document. The opposite transformation could then be performed to convert the incoming XML bug report into an ADO recordset that the Visual Basic 6.0 component could easily process.
Instead of writing code to convert between ADO recordsets and XML, the development team decided to rewrite the bug reporting class in Visual Basic .NET to take advantage of ADO .NET and XML-based datasets. Doing this allowed them to easily expose the data to the client application as XML while still interacting with the data via an easy-to-use object interface within the Visual Basic .NET component.
Normally, writing the wrapper code to convert between data formats is a safer choice, but since one of the goals of the migration project was to gain practical experience with the new technologies, it made sense to convert.
Migrated Site Design At this point, the team had accomplished what they set out to do at the beginning of the project. The existing customer Web site had been migrated to ASP .NET and in the process a number of features provided by the .NET Framework were incorporated successfully. The team was also able to enhance and extend the site by writing new features from the ground up in Visual Basic .NET without changing the entire code base of the site. Figure 7 illustrates how the architecture of the site has changed from the original release to this article's press time.
Figure 7 The New Architecture
The new architecture and Web site allows the Visual Studio .NET and .NET Framework development teams to further improve their relationship with the beta test sites. The new bug reporting capabilities feed into the existing bug reporting architecture and into the hands of the development team who can resolve the issues. In addition, the migrated site provides the teams with an opportunity to gain experience in a production environment.
Lessons Learned The process of migrating beta.visualstudio.net showed that there are a number of development techniques that can be used today with Visual Basic 6.0 and ASP that will make the migration to .NET easier. The techniques identified are good programming practices that will allow you to maintain your application more easily whether you migrate to Visual Studio .NET or not.
Two things you can do now to make migration easier later are:
The ability for ASP .NET and Visual Basic .NET to communicate with existing COM+ components makes migrating applications a straightforward process. The interoperability layer allows you to limit the amount of application code that has to be modified to bring an application forward to the .NET platform. You can migrate only what you need to and extend your application's functionality by building new components in Visual Basic .NET and ASP .NET while still using your existing code base.
- Don't rely on default object properties. Always explicitly reference default properties within your application.
- When calling methods, you should put parentheses around the parameter list.