Microsoft's ASP.NET development environment provides an exciting new technology for creating Web-based applications that includes functionality not readily available in "classic" ASP. This document introduces ASP.NET and examines a few of the reasons why migrating ASP applications to ASP.NET is worthwhile. Topics
- Active Server Pages: Pros and Cons
- What is the .NET Framework?
- ASP.NET Pros
- Language Choice
- Code Compilation
- Server Controls
- User Controls
- Session Management
- Recommendation of Best Practices
Microsoft's release of Active Server Pages (ASP) spawned a new revolution in Web application development that provided developers with a powerful server-side platform for creating dynamic Web applications. ASP's success can be tied to several factors including its scripted language environment, the ease with which data can be integrated into Web pages, and its overall low learning curve. These positive factors along with others have made it one of the most popular Web application development technologies in the world.
No matter how good a particular technology is there are always inadequacies that are discovered as the technology matures. ASP is no exception. Microsoft realized this early on through customer interaction and feedback. They knew that although ASP as very good at allowing developers to rapidly create dynamic Web sites, a new and improved technology needed to be developed to fill in some of the technology gaps. The technology they developed to fill these gaps is now known as the .NET Framework. Before discussing some of the pros found in the .NET Framework and ASP.NET, let's take a quick look at a few of the ASP technology gaps that Microsoft needed to fill.
Active Server Pages: Cons
ASP Web pages are driven by scripting languages such as VBScript, JScript, or even PerlScript. While this provides a rapid development environment, it means that each ASP page must be interpreted (read from top to bottom) each time a client request comes into the Web server. While interpreted code is easy to write (it isn't compiled), it's not the most scalable and doesn't lend itself well to the principles of object-oriented programming (OOP) which have become so popular. Because ASP script code is generally embedded within HTML, the code can also become difficult to read and maintain as pages become more and more complex. ASP developers affectionately refer to this phenomenon as "spaghetti code."
In addition to these issues, ASP typically requires developers to write a lot of code to perform common tasks such as adding data to a drop-down list or paging through an HTML table that displays customer records. Database records must be programmatically walked through using ActiveX Data Objects (ADO) and dynamically injected into HTML code. Although this process is not overly difficult and can be simplified by placing reuseable code in include files, it isn't nearly as simple as it should be.
Extending ASP functionality can also be somewhat cumbersome as more advanced functionality must be added through COM components written in languages such as C++ or Visual Basic. These components must be "registered" in the Windows operating system registry in order to be used, which makes deployment to Web servers that much more difficult and error prone. In addition to their reliance on COM, ASP pages have limited caching functionality that can be used to store frequently accessed pieces of information. The lack of caching support doesn't provide the best environment for building scalable Web sites. Finally, although the availability of sessions in ASP pages can certainly be viewed as a pro due to the ease that state can be stored between client requests to the Web server, ASP session state is stored in-process on the server. This ultimately reduces the scalability of an application and makes it difficult to spread the load across multiple servers found in a Web Farm. While the cons mentioned here are not meant to detract from the success of ASP, they're highlighted to illustrate some of the main issues that Microsoft needed to resolve. Rather than resolve these issues through enhancing ASP, they chose a completely different road with their release of the .NET Framework and ASP.NET.
What is the .NET Framework?
If you're unfamiliar with the .NET Framework, it is an object-oriented development platform that can be used to create Web-based, Client-Server, XML Web Service, and wireless applications. The framework offers numerous development, scalability, and architectural advantages over Microsoft's previous Component Object Model (COM) approach through providing a central execution engine referred to as the Common Language Runtime or CLR. Because the .NET framework and the CLR do not rely on the Windows registry (no more regsvr32.exe), developers can easily deploy .NET applications without being forced to create elaborate setup packages. .NET's CLR handles virtually all aspects of code execution. This includes handling memory management and garbage collection, supporting multiple languages such as C# and VB.NET, managing security, and performing Just-in-Time (JIT) code compilation. Although CLR specific topics won't be covered in this article, you can read more about them in the .NET Software Developers Kit (SDK) that is freely downloadable from http://msdn.microsoft.com/netframework/downloads/howtoget.aspx
Although at first glance it may seem that ASP.NET is simply a minor upgrade from ASP due to the name similarities, don't let the name mislead you. Rather than enhancing the technology found in ASP, Microsoft's release of the .NET Framework and ASP.NET offers a completely new way of developing applications. ASP.NET contains many new features that allow for greater developer productivity and enhanced application scalability and stability. Microsoft made these features available while still allowing "classic" ASP applications to run on the same server as ASP.NET applications. This is possible due to a new .aspx file extension used by ASP.NET Web pages. Note, however, that running ASP.NET Web applications requires Internet Information Server (IIS) 5 or higher.
In order to understand best practices for migrating existing ASP applications to ASP.NET, let's take a look at a few ASP.NET features starting with language supportand code compilation. However, there are many advantages to porting your application from ASP to ASP.NET. Some of the biggest advantages include:
- Increased performance: Microsoft tests have shown that ASP.NET applications can handle two to three times the requests per second as classic ASP applications.
- Increased stability: Processes are closely monitored and managed by the ASP.NET run time, so that if one misbehaves (leaks, deadlocks), a new process can be created in its place, which helps keep your application constantly available to handle requests.
- Increased developer productivity: New features like server controls and event handling in ASP.NET help developers build applications more rapidly and in fewer lines of code. It is also easier than ever to separate code from HTML content.
One of the most notable changes from ASP to ASP.NET is the way code executes when a page (now called a Web form) is requested on the server. ASP.NET no longer relies on scripting languages such as VBScript to execute code. This provides faster page execution times and greater scalability since the compiled code provides a "roadmap" for the execution engine. It also allows many errors to be entified during the compilation process rather than at run-time. The language used to write ASP.NET Web forms varies reatly from person to person. Currently the .NET Framework supports over 24 different languages ranging from VB.NET to Cobol.NET to Eiffel. While this language choice may sound enticing, in reality you'll probably choose one of the more ainstream languages such as VB.NET or C# depending upon your background. If you come from a Visual Basic or VBScript background, VB.NET will likely be your language of choice. If you come from a C++, C, Java, or J++ background, then C# may be better suited for you.
Figure 1 provides a simple example of VB.NET and C# code that would be executed when an ASP.NET page first loads. Notice that the code is strongly-typed which provides better performance and stability, and makes code less error-prone.
Public Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
'Hit when the ASP.NET Web form first loads
public void Page_Load (object sender, EventArgs e)
//Hit when the ASP.NET Web form first loads
Figure 1. VB.NET and C# are two of the mainstream .NET languages used to create ASP.NET Web applications. The code shown here is executed each time an ASP.NET page is requested on the Web server.
As code within an ASP.NET Web form is compiled (using built-in language compilers), a special type of code called Microsoft Intermediate Language (MSIL) is generated within the assembly (the .dll file created by the compiler). As its name implies, MSIL is an intermediate language that is recognized by the Common Language Runtime (CLR). When an ASP.NET page is first executed, MSIL is automatically converted into native machine code using the CLR's Just-in-Time compiler, which provides optimal performance of the code. Figure 2 demonstrates the compilation process.
Figure 2. All .NET language code (C#, VB.NET, etc.) is compiled into Microsoft Intermediate Language (MSIL). When an ASP.NET page is first requested, the MSIL is converted into native machine code by the CLR's Just-in-Time compiler.
Seemingly simple tasks such as adding dynamic data from a database to a drop-down list or table can require that a lot of code be written in ASP. Fortunately, much of this coding is eliminated in ASP.NET through using new "controls" referred to as Server Controls. Server Controls are pieces of code supplied by Microsoft or other third parties that are capable of generating browser specific HTML. A list of commonly used ASP.NET Server Controls is shown below (many other controls exist):
- DropDownList - Creates an HTML <select> tag with <option> tags.
- DataGrid - Creates a fully pageable, editable, and selectable table of data using the HTML <table> tag.
- Calendar - Creates HTML for a calendar using a <table> tag.
- Button - Creates an HTML <input> tag that is capable of raising "events".
- TextBox - Creates standard, password, or multi-line textboxes using the <input> and <textarea> HTML tags.
To show how powerful server controls are, let's take a quick look at how easy it is to create a monthly calendar using ASP.NET's Calendar control. Figure 3 shows the code you need to add into an ASP.NET page (named Calendar.aspx) to create a basic calendar. Figure 4 shows the result that is generated when the ASP.NET page is called.
<h2>ASP.NET Calendar Control</h2>
<form runat="server" ID="Form1">
<asp:calendar id="calMonths" runat="server" />
Figure 3. The Calendar control is capable of generating fully functioning calendars with minimal effort on the developer's part. If you've ever had to write a calendar for ASP applications, you'll appreciate how much time is saved by using the ASP.NET Calendar control.
Figure 4. The ASP.NET Calendar control makes creating calendars a snap. Although not shown, events, meetings, and other data can be added to the calendar without writing a lot of code. The calendar's look and feel can also be customized.
All ASP.NET Server Controls start with the "asp" prefix and are followed by the name of the control. Although the "id" attribute is optional it is recommended since it can be used to identify the control programmatically. The runat="server" attribute and associated value is required. Server Controls such as the Calendar control simplify coding and allow
relational, XML, or other data to be associated with the control using .NET languages such as C# or VB.NET.
ASP Web developers are quite familiar with the concept of include files. These files allow frequently used code or HTML (such as headers or footers) to be stored in text files that can be re-used throughout a Web site. An example of the ASP syntax used to reference an include file named Header.inc is shown below:
<!--#Include Virtual="/Includes/Header.inc" -->
While include files are quite powerful and can greatly simplify the maintenance of a Website, they do have a few shortcomings. First, ASP does not provide a convenient way to dynamically add an include file into a Web page. To illustrate this, consider the common scenario where several include files (weather, news, markets, etc.) need to be
dynamically added into a Web page depending upon a user's selected preferences. To handle this task each include file is typically added into a large If statement or Select Case code block which makes it more difficult for other include files to be dynamically added to an application in the future. An example of this is shown below:
'Hit when the ASP.NET Web form first loads
'Read in user preference from cookie or db into
pref = GetUserPref()
Select Case pref
<!--#Include Virtual="/Includes/Weather.inc" -->
<!--#Include Virtual="/Includes/News.inc" -->
<!--#Include Virtual="/Includes/Markets.inc" -->
<!--#Include Virtual="/Includes/Default.inc" -->
Second, include files do not make it easy for HTML coders to supply additional information that the include file may use to alter the way it functions or to alter the HTML that it generates. As an example, there is no way to supply the starting date to an include file that creates an HTML calendar using pure HTML code (without resorting to using the QueryString anyway). Instead, VBScript or JScript code must be used to assign the start date to a variable in the include file. Finally, include files are not compiled or automatically cached, which is not optimal for performance and scalability.
Although ASP.NET still supports the concept of include files, it offers a more powerful object-oriented alternative called "user controls." User controls are special files that can dynamically be loaded with very little programming code, allow HTML coders to easily supply additional data needed by the control, and offer better performance through compiled code.
To create a user control, a special directive named Control must be added at the top of the control's code: <%@ Control %>. The user control file must then be saved with a .ascx extension. The user control can define properties (items that help describe the user control or allow data to be passed to it) that can make it easier for HTML coders to perform advanced tasks without actually understanding programming. To add a user control into an ASP.NET Web page, two different coding steps must be performed. First, a special Register directive must be added to the top of the ASP.NET page. This directive has several attributes as shown below:
<%@ Register TagPrefix="Acme" TagName="Calendar" src="UserControls/Calendar.ascx" %>
After the user control is registered, it can be added anywhere within an ASP.NET Web page by referencing the defined TagPrefix and TagName values and by adding the runat attribute:
<Acme:Calendar id="ucCalendar" runat="Server" />
Calendar.ascx to be run that would output calendar HTML code. Assuming the Calendar.ascx user control defined a property named StartDate, the initial date displayed by the calendar could be set by using the following code:
<Acme:Calendar id="ucCalendar" StartDate="10/2003" runat="Server" />
Many other useful tasks can be performed with user controls including caching (caching is covered next) and dynamically loading them into a Web page. Since this section started out by showing how much code would be required to dynamically load include files in ASP, let's finish the section off by showing the same process using ASP.NET user controls. Figure 5 demonstrates how to dynamically load a user control into an ASP.NET
Web page using either VB.NET or C# code.
//Dynamically load a user control
UserControl ctl = (UserControl)Page.LoadControl(path);
'Dynamically load a user control
Dim ctl As UserControl = CType(Page.LoadControl(path), UserControl)
Figure 5. User controls can dynamically be loaded into an ASP.NET Web page by using the LoadControl() method associated with the Page class. This technique is much easier to work with as compared to "classic" ASP and provides greater flexibility.
Caching is the process of temporarily storing frequently accessed data to enhance the scalability and performance of a Web application. For example, assume that several news stories located in a database need to be displayed on the homepage of a Web site.
Without caching, the database must be queried each time a user hits the page. This causes the database to work harder than it really needs to given that all users share the same data. ASP does contain a basic type of caching exposed through a special kind of state referred to as Application state. Data added into ASP Application state is available to all users visiting the Web application. Although Application state is very useful in a variety of circumstances, it provides no type of automatic expiration for the content being stored.
Although ASP.NET still supports Application state, a completely new caching mechanism with automatic content expiration and decay is now available to developers. This allows data caches to automatically expire and be refreshed without forcing the
developer to write any code. Data caches can even be linked to files so that a given cache is invalidated and then refreshed when the linked file changes in some manner.
Aside from caching data (such as news headlines), ASP.NET cache objects can also be used to cache entire Web pages or even portions of Web pages, which can greatly enhance a Web site's scalability and allow database servers to focus on more intensive tasks. This type of functionality can be injected into a page by adding a special page "directive" called OutputCache to the top of the page. A simple OutputCache directive designed to cache an entire ASP.NET page for 60 seconds is shown below:
<%@ OutputCache Duration="60" VaryByParam="none" %>
In cases where only portions of a page need to be cached, this directive can be added into user controls.
Microsoft provided a great way to make the Web "stateful" through the use of ASP sessions. Sessions allow customer data such as shopping carts to be remembered between calls to the Web server with minimal effort. However, ASP sessions can cause scalability bottlenecks on high-volume sites because the session data is stored "in-process" on the Web server. Plus, ASP sessions are only good on the server where they are created, which poses a problem when Web farms need to be utilized to maximize a Web site's availability.
Although "in-process" sessions are still available in ASP.NET, two other options now exist including state servers and SQL Server. Rather than storing sessions directly on the Web server, ASP.NET sessions can now be stored on a dedicated state server that can be shared by multiple Web farm servers. Sessions can also be stored in a SQL Server database. This provides better scalability and availability of sessions. Storing sessions in these data stores can be accomplished by using the same code you may have used in ASP. Code such as Session("CustomerName") = "John Doe" still works. Rather than requiring a change in coding as you switch between the three storage options, a configuration file named web.config can be modified to contain the desired session storage location. Figure 5 shows a portion of the web.config file that relates to session storage.
<sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="" cookieless="false" timeout="20" />
Figure 5. Sessions can be stored three different ways in ASP.NET. This code shows how the web.config file can be edited to store session data on a dedicated state server. Notice that sessions can now be leveraged without cookies being enabled on the client browser. This is done by setting the value of the cookieless attribute to "false". The mode attribute specifies where you would like to store your state information. Your options are Inproc, StateServer, SqlServer, or Off.
Table 1. Session State Storage Information
Session state is stored locally on this server (ASP style).
Session state is stored in a state service process located remotely or potentially locally.
Session state is stored in a SQL Server database.
Session state is disabled.
StateConnectionString and sqlConnectionString obviously come into factor if you use one of these other options. You can only use one storage option per application.
Security is another area that requires a great deal of focus. Here is a brief overview of the ASP.NET security system. ASP.NET security is primarily driven from settings in the security sections of your web.config file. ASP.NET works in concert with IIS to provide a complete security model for your application. IIS security settings are some of the few application settings that will actually carry over and be applied to your ASP.NET application in a similar manner to that in ASP. There are, of course, many additional enhancements.
For authentication, ASP.NET supports the different options shown in Table 2. Table 2. ASP.NET Authentication Options.
Table 2. ASP.NET Authentication Options
ASP.NET uses Windows authentication.
Cookie-based, custom login forms.
External Microsoft provided Passport Service.
No authentication is performed.
These are the same options you have in ASP, with the exception of the new Passport authentication option. As an example, the following configuration section enables Windows-based authentication for an application:
Once your users have been authenticated, you can focus on authorizing what resources you would like them to have access to. The following sample shows access being granted to "jkieley" and "jstegman," while everyone else is denied access.
<allow users="NORTHAMERICA\jkieley, REDMOND\jstegman"/>
As a refresher, impersonation refers to the process whereby an object executes code under the identity of the entity on whose behalf it is performing. In ASP, impersonation will allow your code to run on the behalf of an authenticated user. Alternately, your users can run anonymously under a special identity. By default, ASP.NET does not do per-request impersonation. This is different from ASP. If you rely on this capability, you will need to enable this in your web.config file as follows:
<impersonation enable = "true"/>
Recommendation for Best Practices
Now that you have been exposed to most of the issues you are likely to encounter, you may be wondering what things you can do today to be better prepared for them when you finally move to ASP.NET. Quite a few things can be done that will make the process smoother. Many of these suggestions will be beneficial to your ASP code even if you do not move to ASP.NET until sometime in the future.
- Use parentheses and Call statements wherever possible, as detailed earlier in this article. In ASP.NET you will be forced to use parentheses. Using the Call statement today will help you add a bit of discipline that
will better prepare you for the future.
- Avoid nested include files. That means, you should try to eliminate any areas where you have include files that include other include files. What tends to happen over time is that your code ends up relying on a global variable that is defined in an include file somewhere else, and you are getting access to it only because you have included another file that includes the one you really need. When you migrate to ASP.NET, you will most likely be moving your global variables and routines into class libraries, in which case, it is much easier to do if you have a clear picture of where you are getting access to everything. You may end up having to move things around and change some routines' names that were duplicated in multiple files.
- One strategy used in the migration process is to migrate all of the utility functions and code contained in your server-side include files into Visual Basic or C# class libraries. This allows you to finally put all of the code where it belongs-in objects, as opposed to multiple-interpreted ASP files.
- If you have a bunch of global variables or constants mixed in server-side include files, consider placing all of them in a single file, as well. Once you move to ASP.NET, you can then easily create a class that will house your global or constant data. This will make for a much cleaner and more maintainable system.
- If at all possible, you should separate your code from HTML content. Clean up functions that mix code and script throughout a function body. Doing so puts you in a much better position to leverage code-behind as this is the ideal model under ASP.NET anyway.
- Make sure you explicitly call any close() or cleanup methods that exist on the objects and resources you may be using. We all know how forgiving Visual Basic and VBScript are when it comes to cleanup. Normally, they are pretty good at cleaning things up immediately but, as we move to .NET and the garbage-collected world, one cannot be sure exactly when objects will be cleaned up. If you can cleanup and release your resource explicitly, you should.
If possible, you should avoid intermixing server-side VBScript and JScript in the same page. In general, this is a poor programming practice anyway. This is also a migration issue for ASP.NET in that it requires only one inline <% %> language per page because of the new compilation model. You can continue to emit client-side script in the same manner as you are used to.
This document covered some of the more powerful features that can simplify Web development while providing a more scalable, stable, and productive environment. Although there is certainly a learning curve associated with migrating from ASP to ASP.NET, the effort is well worth it due to the numerous productivity features offered by the .NET framework and ASP.NET.