Almost all the issues you encounter when migrating your classic ASP applications to ASP.NET fall into two categories: page structure changes and language changes. The next two sections discuss the types of changes in each category and the ways you need to update your code to work with them.
The page structure changes from classic ASP to ASP.NET can be broken down into two areas: changes in the structure of code blocks and changes to the syntax of page directives.
As discussed in Chapter 7, there are significant changes between how code was structured in classic ASP and how it is structured in ASP.NET. These changes, which are designed to make your code more readable and maintainable, are likely to be the most common issue in migration.
In classic ASP, server-side code is written in either code render blocks, indicated by the syntax <% %>, or code declaration blocks, indicated by the <script runat=“server”></script> syntax. Either syntax can be used anywhere in the page and can contain either statements or procedures.
One problem with classic ASP was that it can be difficult to tell the order in which its code will execute, which can cause bugs. It’s also all too easy to write spaghetti code, wind up with a page covered in render blocks, and mix procedures and raw statements. This can make the code difficult to read and maintain, and mixing HTML and render blocks often negatively affects page performance.
In ASP.NET, the purpose of render blocks and code declaration blocks has been narrowed considerably. Render blocks in ASP.NET can contain only executable statements, not procedures, whereas code declaration blocks can contain only global variable declarations and procedures.
Important |
In addition to the performance and reliability implications of mixing code within render blocks and HTML, using render blocks also makes for an unclear separation of presentation and program logic. ASP.NET enables one team to work on the presentation logic (in the .aspx files) while another group works on the guts of the application logic (in the .cs files). |
Another significant difference between classic ASP and ASP.NET is that in classic ASP, multiple <script runat=“server”> code declaration blocks can be used on a page. Each code declaration block could use a different language through the language attribute, which could be set to VBScript or JScript. ASP.NET only supports a single language per page, which is Visual Basic .NET by default.
Classic ASP pages using render blocks always executed from top to bottom. Code in <% %> render blocks was executed and output to the response stream as the ASP interpreter encountered it.
ASP.NET code is compiled into an instance of the Page class, and execution is event-based. Rather than placing start-up code in the first render block in a page, start-up code in ASP.NET is placed in the Page_Load event handler, which is fired when the instance of the Page class that represents the page is loaded into memory. Likewise, a Page_UnLoad event is fired just before the page is removed from memory and can be used to run any clean-up code that is necessary.
In classic ASP, the primary directive used in pages was the @ Language directive, which specified the language to be used for render blocks. Other less commonly used directives included @ Codepage, @ EnableSessionState, @ LCID, and @ Transaction.
In ASP.NET, these directives are attributes of the @ Page directive, which should appear at the top of each ASP.NET Web Form page. See Chapter 7 for a full discussion of the @ Page directive and its attributes.
One new attribute of the @ Page directive that is important to discuss in relation to classic ASP is the AspCompat attribute. By default, ASP.NET runs as a multi- threaded apartment (MTA) process. This means that single-threaded apartment (STA) components, such as those written in Visual Basic 6.0, are not compatible with ASP.NET. This includes the ADO components, which are installed to run as STA components by default. (You can modify this by running a batch file that changes the registry settings for ADO, but that is beyond the scope of this discussion.) Setting the AspCompat attribute to true forces ASP.NET to run in STA mode, making it possible to use STA components in ASP.NET pages.
Important |
Setting AspCompat to true should be considered a short-term solution when migrating from ASP to ASP.NET, because this setting can have a significant negative impact on the performance of your application. For best performance, you should rewrite components written in earlier versions of Visual Basic using Visual Basic .NET, and migrate existing ADO code to use ADO.NET. |
In addition to changes to the structure of pages in ASP.NET, there are some significant changes when moving code from VBScript to C# that will require modifications to your code. These include the following:
Set and Let are not needed or supported. Object references can be set by simple assignment:
Object1 = Object2;
Parentheses are required for calling all methods in C#, including methods that do not have parameters:
Response.Write("Hello, World! ");
All statements are terminated with semicolons.
Blocks that are associated with control structures like if and while statements are delimited by curly braces ({ and }) rather than words, such as Endif or End While.
The Variant data type does not exist in C# .NET. The replacement is Object.
Default properties are not supported. All properties must be called explicitly:
MyString = TextBox1.Text;
Property declaration syntax is different in C#. Instead of Property Set, Property Get, and Property Let, C# .NET uses the following syntax (keep in mind that value is a special keyword that contains the value submitted to the set portion of the public variable statement):
public string MyPropert ge return MyInternalVariable se if ( value!=MyInternalVariable MyInternalVariable=value }
Important |
The property just shown acts as a simple shell for MyInternalVariable. You can use any code while setting or getting the property. In this example, I only set MyInternalVariable in the setter if it is different from the current value. Properties can be used to expose values that don’t really exist as explicit fields in the class. For instance, you might create an Invoice class that exposes an InvoiceTotal property that cannot be set, and when read actually totals the amounts in each invoice line. You can also use properties to expose objects that might take some time to create. By doing so, you can postpone the expensive creation until the object is first requested, allowing Just-In-Time initialization. |
By default, parameters are passed to procedures in C# by value. Parameters can be passed by reference using the ref keyword. You can change the value of Reference parameters in the procedure to which they’re passed and then retrieve their value outside the procedure:
public void MySub(ref string MyValue MyValue="Hello! " }
To demonstrate some of these changes and show you how to deal with them, let’s walk through the process of migrating a classic ASP page that accesses data in a SQL Server database through ADO and writes it to the page as an HTML table. You will migrate the ADO to ADO.NET and change the language from VBScript to C#. Rather than rendering a table directly, the ASP.NET version uses a DataGrid component. The following listing shows the classic ASP page you’ll use to start. You will need to set the pwd attribute in the connection string to the appropriate password for your VSdotNET MSDE instance. You might also want to change the uid attribute to the name of an account with fewer privileges than the sa account. You can get the values of both of these attributes from your SQL Server administrator.
<%@ Language=VBScript %> <html> <head> < Dim objCon Dim objCm Dim objR Dim strCon ' Do NOT use the sa account in data access code, as shown i ' the connection string below! Doing so is a MAJOR security risk ' Change the connection string to either use a trusted connection ' or to use a less-privileged account to access the database strConn = "PROVIDER=SQLOLEDB;INITIAL CATALOG=PUBS; " & "SERVER=(local)\VSdotNET;uid=sa;pwd=; Set objConn = Server.CreateObject("ADODB.Connection" Set objCmd = Server.CreateObject("ADODB.Command" Set objRS = Server.CreateObject("ADODB.Recordset" objCmd.CommandText = "SELECT * FROM Authors objConn.Open strCon Set objCmd.ActiveConnection = objCon Set objRS = objCmd.Execut Sub FormatTabl Dim objFiel If Not objRS.EOF The Response.Write "<table border=2 cellspacing=0> Do While Not objRS.EO Response.Write "<tr> For Each objField In objRS.Field Response.Write "<td>" & objField & "</td> Nex Response.Write "</tr> objRS.MoveNex Loo Response.Write "</table> Els Response.Write "No Records! End I End Su Sub CleanUp( objConn.Clos Set objConn = Nothin Set objCmd = Nothin Set objRS = Nothin End Su %> </head> <body> < FormatTable( CleanUp( %> </body> </html>
The following illustration shows the output of this page.
The page in the previous listing accesses the Authors table of the Pubs SQL Server sample database (in this case in the VSdotNET MSDE instance that can be installed with Visual Studio .NET), calls a render function to write the data to the page as an HTML table, and then calls a clean-up function to close the connection to the database and set the object references to Nothing to ensure that the COM subsystem knows these objects can be destroyed.
Important |
One thing this sample code has in common with much of the sample code you will encounter (and unfortunately, some production code as well) is its use of the sa SQL Server login account with a blank password. (This is the default for SQL Server 6.5 and 7.0 installs. You must explicitly choose a blank password to use a blank sa password in SQL Server 2000.) In practice, the sa account should always be given a strong password because this account has full administrative rights on the SQL Server machine. This includes the ability to run operating system commands through an extended stored procedure. You should never, under any circumstances, use the sa account for accessing data from a page. All it takes is a single bad page to compromise an entire server, especially when your page provides system administrator access to SQL Server. If you cannot use a trusted connection to SQL Server, you should set up one or more special user accounts for each Web application with the absolute minimum rights necessary to allow access to that application’s data. This will reduce the risk of overbroad rights, which can cause data to be compromised. Another security issue in the sample is the placing of user ID and password information directly in the page. In practice, if you are connecting to a database with an explicit username and password, connection string information should be stored somewhere more secure. In order of increasing security, options include storing it as an appSetting in Web.config, storing it as an appSetting in Machine.config (not appropriate in a shared server environment), and hard-coding it as a private member of a compiled component. See the section entitled “Storing Database Connection Strings Securely” at http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetch12.asp for more information on this topic. |
In the short term, your goal might be to simply move your pages over to ASP.NET while still using most of the existing logic in the page. Although this choice has performance implications, it might make your migration easier by letting you do it in stages. Making the code in the previous listing work as an ASP.NET page is largely a matter of modifying it to comply with the rules for ASP.NET code using Visual Basic .NET. The conversion from VBScript to Visual Basic .NET is beyond the scope of this book.
Doing a quick-and-dirty conversion to allow your VBScript ASP pages to run as ASP.NET pages using Visual Basic .NET is a stopgap measure that will enable you to get the page up and running quickly. Among other compromises, you will need to modify the ASP.NET default to allow STA components to work correctly with ASP.NET. In the long run, it’s best to fully migrate your code to take advantage of the features offered by ASP.NET and ADO.NET. The following steps show how to migrate the ASP page to run under ASP.NET in C#.
Open Visual C# .NET. Create a new project called Appendix_A.
To rename the initial default page, on the File menu, click Save WebForm1.aspx As. In the resulting dialog box, type GetAuthors.aspx as the new file name, and click the Save button.
Move the mouse pointer to the Toolbox, and drag a DataGrid onto the Web form. Change the ID of the DataGrid to MyGrid.
On the View menu, click Code, or press F7 to move to the code window.
Add the following line to the using clauses:
using System.Data.SqlClient;
Scroll down to the Page_Load event handler and add the following code:
private void Page_Load(object sender, System.EventArgs e // Put user code to initialize the page her DataSet MyDS = new DataSet() SqlConnection MySqlConn SqlDataAdapter MySqlDa string ConnStr string SQLSelect ConnStr=@"server=(local)\VsDotNet;database=pubs; " "Trusted_Connection=yes" SQLSelect="SELECT * FROM Authors" MySqlConn=new SqlConnection(ConnStr) tr MySqlDa=new SqlDataAdapter(SQLSelect,MySqlConn) MySqlDa.Fill(MyDS) MyGrid.DataSource=MyDS.Tables[0].DefaultView DataBind() // finally block ensures that the connection will be closed // even if an exception occurs finall MySqlConn.Close() }
Save the file and its code-behind module, and then build the project.
Note |
To use a trusted connection to connect to SQL Server as shown in the preceding listing, you will need to either enable Windows authentication and impersonation or set up the ASPNET worker process account as a SQL Server login, as described in Chapter 9. |
Browse GetAuthors.aspx using Microsoft Internet Explorer. The output should look similar to the following illustration.
Switch to GetAuthors.aspx by clicking the appropriate tab near the top of the Visual Studio .NET editing window. Ensure that you are in Design mode by clicking Design on the tab control at the bottom of the Design window.
Right-click the DataGrid and click Auto Format on the shortcut menu. The screen that appears will look like the illustration on the next page.
In the AutoFormat dialog box, click Professional 1 in the Select A Scheme box, click OK, and then save the page.
Browse GetAuthors.aspx again, using Internet Explorer. The screen that appears will look similar to the following illustration.
Note |
The code in the preceding listing offers better performance than a quick-and-dirty conversion of the VBScript code to Visual C# .NET because it does not rely on AspCompat to run. It takes advantage of ADO.NET instead of using ADO through COM Interop (which carries some performance overhead). The code could be made even more efficient by using an ADO.NET DataReader to access the data. The code in the preceding listing also provides greater flexibility for modifying the look of the rendered table. You can modify this by adding attributes to the DataGrid tag. Using an ASP.NET DataGrid also provides built-in support for paging, editing, and filtering. Fancy formatting (including alternating item formatting) is also easy to add, as shown in Step 17 of the previous procedure, using Visual Studio .NET’s Auto Format. See Chapter 9 for more information on these features. |
As you can see from this appendix, migrating from classic ASP to ASP.NET does not need to be terribly painful. However, a lot depends on how your classic ASP code is written in the first place. Code that is written with a great deal of intermingled HTML and render blocks will be more difficult to migrate, as will code that does not follow good coding practices. The following are several coding practices you can put in place in your ongoing classic ASP development to make migrating it to ASP.NET easier:
Use ByVal or ByRef to explicitly state which type of parameter is desired in procedures that take parameters. This will remind you what types of parameters are expected when moving to ASP.NET and C#.
Write all procedures in <script> code declaration blocks, rather than in render blocks.
Use render blocks sparingly, particularly when intermingled with HTML tags.
Do not rely on default properties. Instead, explicitly name properties such as objRS.Value.
Do not use multiple languages in server-side <script> blocks. Choose the language you’re most comfortable with and use it exclusively on a per-page basis.