Friday, September 21, 2007

ASP.NET Tip: Persistent Logins Under ASP.NET 2.0


However, ASP.NET 2.0 has changed how the forms authentication tickets work. Simply using the same method with a True argument won't actually persist the cookie. If you want to have a significantly longer timeout for your forms authentication ticket, the code in this tip performs the same steps as the built-in FormsAuthentication methods but gives you more control over the specifics of how it works.

For starters, you'll need to add a block to your Web.config to enable FormsAuthentication:

<authentication mode="Forms">
<forms name="MyApplication" loginUrl="/login.aspx" />

If you want to switch into SSL mode for the login, you can specify the full URL, including the "https://" prefix in the loginUrl parameter. Also add an authorization section to lock down your entire site or virtual directory:

<deny users="?"/>

The code in your login form, after you've done your own validation to see if the user can log into your application, looks like this:

FormsAuthenticationTicket t =
new FormsAuthenticationTicket(1, userID,
DateTime.Now, DateTime.Now.AddMonths(3),
chkSave.Checked, userID.ToString(),

string encTicket = FormsAuthentication.Encrypt(t);

HttpCookie c = new HttpCookie(FormsAuthentication.FormsCookieName,

if (chkSave.Checked)
c.Expires = DateTime.Now.AddMonths(3);


In this example, the userID variable is the value that will be available if you look at User.Identity.Name after the user has logged in. On my page, chkSave is a check box that lets the user indicate whether or not to save the password. That true/false value is passed into the FormsAuthenticationTicket constructor to mark the ticket as persistent or not. After you get the ticket back, encrypt it and then put it into the designated cookie.

If the user has chosen to save the cookie, the cookie needs to be assigned an expiration date. In this case, I'm using three months as the expiration timeframe.


Technorati Tags: , , , , ,

Edit and Encrypt Web.Config Sections Using C# 2.0


ASP.NET 1.x allowed configurations in web.config file to be read from a .NET application. But, there were no options to manipulate Web.Config contents programatically. To achieve this, you had to consider the Web.Config file as a normal file or an XML file. .NET 2.0 fills this gap and also provides many other useful operations to be carried out on a Web.Config file, such as editing and encrypting sections of the Web.Config file. This articles illustrates these functionalities via a sample ASP.NET application.

The classes and methods to take control of the Web.Config file span across two namespaces:

Each section in the Web.Config file has a corresponding class in either of the namespaces. These classes allow modification of the corresponding sections. The classes for sections within the "system.web" section are found in System.Web.Configuration. Classes for other sections that are not specific to Web.Config are found in System.Configuration.

Modifying a section in Web.Config
  1. Open Web.Config for editing by using the WebConfigurationManager class.
  2. Use the respective Configuration class to make the necessary changes.
  3. Save the changes to the physical file by using the Configuration class.
private void UpdateConfig(string strKey, string strValue)
Configuration objConfig =
AppSettingsSection objAppsettings =
if (objAppsettings != null)
objAppsettings.Settings[strKey].Value = strValue;
In the above piece of code, the OpenWebConfiguration() method of the WebConfigurationManager class opens the Web.Config file in the root directory and returns it as a Configuration object. The GetSection() method of the Configuration class accepts the path to a specific section as an argument. The path is the relative path from the root node "configuration". You can refer to deeper nodes (sections, in this context) by their names separated by '/'. For example, to get access to the "authentication" section, provide "system.web/authentication" as the parameter to the GetSection() method. It returns a generic ConfigurationSecton object that can be typecast to the proper configuration section class. In this example, you get hold of the "appSettings" section with the help of the AppSettingsSection class. The AppSettingsSection class instance has a Settings collection property that contains the application setting from the configuration section as key-value pairs. The Settings property can be indexed using key to get the corresponding value. You also can set the value property and call the Save() method of the Configuration object to write configurations in the Configuration instance to the config file.

Deleting an entry in the Web.config file

The Remove() method of the Settings collection deletes an entry from the Configuration instance. The Remove() method accepts the key of the entry to be deleted.

Note: Please do not forget to call the Save() method of the Configuration instance to get the chnages reflected in the physical file.


To iterate through all the key-value pairs in a configuration section, access the string array of keys via the AllKeys property of the Settings collection.

foreach (string strKey in objAppsettings.Settings.AllKeys)
DataRow dr = dt.NewRow();
dr["Key"] = strKey;
dr["Value"] = objConfig.AppSettings.Settings[strKey].Value;

Encrypting sections in Web.Config file

Now come the security issues. At times, the necessity for protecting sections the of config file arises. In .NET 2.0, there are options available to encrypt sections the of Web.config file programatically. The following method encrypts the "appSettings" section in the Web.config file.

private void EncryptAppSettings()
Configuration objConfig = WebConfigurationManager.
AppSettingsSection objAppsettings =
if (!objAppsettings.SectionInformation.IsProtected)
objAppsettings.SectionInformation.ForceSave = true;

The code above opens the Web.Config file for modification. It then retrieves the "appSettings" section. The ProtectSection() method of the SectionInformation class marks the configuration section for protection. It accepts the name of the protection provider to be used for the encryption. The ForceSave property indicates whether the specified configuration section will be saved even if it has not been modified. Finally, the Save() of the Configuration object writes the configuration settings to the Web.config file. The argument to the Save() method indicates the only properties modified needed to be written to the physical file.

Below is a listing of the "appSettings" section before encryption:

The encrypted "appSettings" section is listed below:

Decrypting sections of web.config file through code is practically identical. The UnprotectSection() method of the SectionInformation class removes the encryption from the configuration section.

private void DecryptAppSettings()
Configuration objConfig = WebConfigurationManager.
AppSettingsSection objAppsettings =
if (objAppsettings.SectionInformation.IsProtected)
objAppsettings.SectionInformation.ForceSave = true;

This encrytion and decryption functionality can be applied to other sections of web.config file also. It comes into use mostly for the "connectionStrings" section where the user name and password usually would be specified. This can done by creating a ConfigurationSection object. An example for the "connectionStrings" section is listed below.

ConfigurationSection objConfigSection = objConfig.ConnectionStrings;

The ConfigurationSection class represents a section within the configuration file. The Configuration class has propertes for each configuration section. This property can be used to get the respective ConfigurationSection objects. This is an alternative to the usage of the GetSection() method of the Configuration class.

Provocative Search Engine Friendly URLs in ASP.NET


Data displayed by dynamic Web sites is usually stored in some sort of backend database. Typically, a numeric ID is associated with a data row of a database table, and all database operations with the table (such as selecting, inserting, deleting, or updating rows) are done by referencing that ID.

More often than not, the same ID used to identify an item in the database is also used in ASP.NET code to refer to that particular item-such as a product in an e-commerce Web site, or an article of a blog, and so on. In a dynamic URL, these IDs are passed via the query string to a script that presents differing content accordingly.

Figure 1 shows a page from This is a demo e-commerce site presented in one of Cristian's books, and employs dynamic URLs. As you can see, the page is composed using data from the database, and the ID that identifies the data item is taken from the dynamic URL.

Figure 1

This is probably the most common approach employed by dynamic Web sites at present, as you frequently meet URLs such as the following:


This approach is certainly the easiest and most straightforward when developing a dynamic site. However, this is about the only benefit these URLs bring. Dynamic URLs come with three important potential drawbacks, however:

  • They are frequently sub-optimal from a search engine spider's point of view.
  • They don't provide relevant keywords or a call to action to a human viewing the URL, therefore reducing the CTR.
  • They aren't easy to remember, or communicate to other parties in the offline world.

Some programmers also tend to use extra parameters freely. For example, if the parameter RefID from the previous example is used for some sort of tracking mechanism, and search engine friendliness is a priority, it should be removed. Lastly, any necessary duplicate content should be excluded from search engines' view using a robots.txt file or a robots meta tag.


If URLs on your site are for the most part indexed properly, it may not be wise to restructure URLs. However, if you decide that you must, please also read Chapter 4 "Content Relocation and HTTP Status Codes" in the book Professional Search Engine Optimization with ASP.NET: A Developer's Guide to SEO (Wrox, 2007, ISBN: 978-0-470-13147-3), which teaches you how to make the transition smoother. It shows how to preserve link equity by properly redirecting old URLs to new URLs. Also, not all solutions to URL-based problems require restructuring URLs; as mentioned earlier, duplicate content can be excluded using the robots.txt file or the robots meta tag.

Numeric Rewritten URLs

An improved version of the previous example is a modified URL that removes the dynamic parameters and hides them in a static URL. This static URL is then mapped, using one of the techniques you'll learn later, to a dynamic URL. The RefID parameter previously alluded to is also not present, because those types of tracking parameters usually can and should be avoided.


The impact of numeric URL rewriting will likely be negligible with the search engines on pages with a single parameter, but it may be significant on pages with two parameters or more. For humans, using numeric URLs can be beneficial when the context makes the URLs hackable, giving those numbers a special meaning. The best example is with blogs, which are frequently employing numeric URLs to reflect the date of the content; for example, will contain the post or posts from July 17th, 2007.

This form of URL is particularly well-suited to the adaptation of existing software. Retrofitting an application for keyword-rich URLs, as covered in the next section, may present additional difficulty in implementation.

Keyword-Rich Rewritten URLs

Finally, here are two ideal keyword-rich URLs:


This is the best approach to creating URLs, but also presents an increased level of difficulty in implementation-especially if you are modifying preexisting source code for software. In that case this solution may not have an easy and apparent implementation, and it requires more interaction with the database to extract the copy for the URLs.


The decision whether to use the .html suffix in the URL is mostly a non-issue. You could also use a URL such as, if you prefer the look of directories.

This "ideal" URL presents a static URL that indicates both to the search engine and to the user that it is topically related to the search query. Usually the keyword-rich URLs are created using keywords from the name or description of the item presented in the page itself. Characters in the keyword string that are not alphanumeric need to be removed, and spaces should be converted to a delimiting character. Dashes are desirable over underscores as the delimiting character because most search engines treat the dash as a space, and the underscore as an actual character, though this particular detail is probably not terribly significant. On a new site, dashes should be chosen as a word-delimiter.

Implementing URL Rewriting

From this moment on, this article discusses URL rewriting. Of particular importance is Scott Guthrie's ASP.NET URL rewriting article. Another interesting article is "URL Rewriting in ASP.NET", by Scott Mitchell.

The hurdle we must overcome to support keyword-rich URLs like those shown earlier is that they don't actually exist anywhere in your Web site. Your site still contains a script-named, say, Product.aspx-which expects to receive parameters through the query string and generate content depending on those parameters. This script would be ready to handle a request such as this:

but your Web server would normally generate a 404 error if you tried any of the following:

URL rewriting allows you to transform the URL of such an incoming request (which we'll call the original URL) to a different, existing URL (which we'll call the rewritten URL), according to a defined set of rules. You could use URL rewriting to transform the previous nonexistent URLs to Product.aspx?ProductID=123, which does exist.

If you happen to have some experience with the Apache Web server, you probably know that it ships by default with the mod_rewrite module, which is the standard way to implement URL rewriting in the LAMP (Linux/Apache/MySQL/PHP) world. That is covered in our book Professional Search Engine Optimization with PHP: A Developer's Guide to SEO (Wrox, 2007, ISBN: 978-0-470-10092-9).

Unfortunately, IIS doesn't ship by default with such a module. IIS 7 contains a number of new features that make URL rewriting easier, but it will take a while until all existing IIS 5 and 6 Web servers will be upgraded. Third-party URL-rewriting modules for IIS 5 and 6 do exist, and also several URL-rewriting libraries, hacks, and techniques, and each of them can (or cannot) be used depending on your version and configuration of IIS, and the version of ASP.NET. In this article we try to cover the most relevant scenarios by providing practical solutions.

To understand why an apparently easy problem-that of implementing URL rewriting-can become so problematic, you first need to understand how the process really works. To implement URL rewriting, there are three steps:

  1. Intercept the incoming request. When implementing URL rewriting, it's obvious that you need to intercept the incoming request, which usually points to a resource that doesn't exist on your server physically. This task is not trivial when your Web site is hosted on IIS 6 and older. There are different ways to implement URL rewriting depending on the version of IIS you use (IIS 7 brings some additional features over IIS 5/6), and depending on whether you implement rewriting using an IIS extension, or from within your ASP.NET application (using C# or VB.NET code). In this latter case, usually IIS still needs to be configured to pass the requests we need to rewrite to the ASP.NET engine, which doesn't usually happen by default.
  2. Associate the incoming URL with an existing URL on your server. There are various techniques you can use to calculate what URL should be loaded, depending on the incoming URL. The "real" URL usually is a dynamic URL.
  3. Rewrite the original URL to the rewritten URL. Depending on the technique used to capture the original URL and the form of the original URL, you have various options to specify the real URL your application should execute.

The result of this process is that the user requests a URL, but a different URL actually serves the request. The rest of the article covers one way to implement each of the preceding steps:

  • URL rewriting with IIS and ISAPI_Rewrite

The book Professional Search Engine Optimization with ASP.NET: A Developer's Guide to SEO also covers these three additional methods.

  • URL rewriting using URLRewriter
  • Writing a custom URL rewriting handler
  • URL rewriting with IIS 7

For background information on how IIS processes incoming requests, we recommend Scott Mitchell's article How ASP.NET Web Pages are Processed on the Web Server.

URL Rewriting with IIS and ISAPI_Rewrite

If your IIS Web server, no matter if it's IIS 5, 6, or 7, has an ISAPI rewriting filter installed, we encourage you to use it, because it's likely to be the most efficient and practical method to implement URL rewriting. When such a filter is used, rewriting happens right when the request hits your Web server, before being processed by the ASP.NET ISAPI extension. This has the following advantages:

  • Simple implementation. Rewriting rules are written in configuration files; you don't need to write any supporting code.
  • Task separation. The ASP.NET application works just as if it was working with dynamic URLs. Apart from the link building functionality, the ASP.NET application doesn't need to be aware of the URL rewriting layer of your application.
  • You can easily rewrite requests for resources that are not processed by ASP.NET by default, such as those for image files, for example.

To process incoming requests, IIS works with ISAPI extensions, which are code libraries that process the incoming requests. IIS chooses the appropriate ISAPI extension to process a certain request depending on the extension of the requested file. For example, an ASP.NET-enabled IIS machine will redirect ASP.NET-specific requests (which are those for .aspx files, .ashx files, and so on), to the ASP.NET ISAPI extension, which is a file named aspnet_isapi.dll.

To intercept incoming requests on an IIS 6-based server, you can create your own URL rewriting ISAPI filter or use an existing one. Creating your own ISAPI filter is too complex a process to cover in this book, but fortunately existing products are available:

Figure 2 describes how an ISAPI Rewrite filter, such as those just listed, fits into the picture. Its role is to rewrite the URL of the incoming requests, but doesn't affect the output of the ASP.NET script in any way.


At first sight, the rewriting rules can be added easily to an existing Web site, but in practice there are other issues to take into consideration. For example, you'd also need to modify the existing links within the Web site content. In Chapter 4, "Content Relocation and HTTP Status Codes", in the book, Professional Search Engine Optimization with ASP.NET: A Developer's Guide to SEO you continue by learning how to properly redirect old links to the new links in a preexisting Web site, to preserve their equity.

Figure 2

ISAPI rewriting filters can be invaluable tools to Web developers tasked with architecting complex dynamic sites that are still search engine friendly. They allow the programmer to easily declare a set of rules that are applied by IIS on-the-fly to map incoming URLs requested by the visitor to dynamic query strings sent to various ASP.NET pages. As far as a search engine spider is concerned, the URLs are static.

The following few pages demonstrate URL rewriting functionality by using Helicon's ISAPI_Rewrite filter. You can find its official documentation at Ionic's ISAPI rewriting module has similar functionality.

In the first exercise, we'll create a simple rewrite rule that translates my-super-product.html (available as part of the code download for the book Professional Search Engine Optimization with ASP.NET: A Developer's Guide to SEO,) to Product.aspx?ProductID=123. This is the exact scenario that was presented in Figure 2.

The Product.aspx Web Form is designed to simulate a real product page. The script receives a query string parameter named ProductID, and generates a very simple output message based on the value of this parameter. Figure 3 shows the sample output that you'll get by loading http://seoasp/Product.aspx?ProductID=3.

Figure 3

In order to improve search engine friendliness, we want to be able to access the same page through a static URL: http://seoasp/my-super-product.html. To implement this feature, we'll use-you guessed it!-URL rewriting, using Helicon's ISAPI_Rewrite.

As you know, what ISAPI_Rewrite basically does is to translate an input string (the URL typed by your visitor) to another string (a URL that can be processed by your ASP.NET code). In this exercise, we'll make it rewrite my-super-product.html to Product.aspx?ProductID=123.


This article covers ISAPI_Rewrite version 2. At the moment of writing, ISAPI_Rewrite 3.0 is in beta testing.

Using Helicon's ISAPI_Rewrite

  1. The first step is to install ISAPI_Rewrite. Navigate to and download ISAPI_Rewrite Lite (freeware). The file name should be something like isapi_rwl_x86.msi. At the time of writing, the full (not freeware) version of the product comes in a different package if you're using Windows Vista and IIS 7, but the freeware edition is the same for all platforms.
  2. Execute the MSI file you just downloaded, and install the application using the default options all the way through.


If you run into trouble, you should visit the Installation section of the product's manual, at If you run Windows Vista, you need certain IIS modules to be installed in order for ISAPI_Rewrite to function.

  1. Make sure your IIS Web server is running and create a http://seoasp/ Web site using Visual Web Developer.
  2. Create a new Web Form named Product.aspx in your project, with no code-behind file or Master Page. Then modify the generated code as shown in the following code snippet. (Remember that you can have Visual Web Developer generate the Page_Load signature for you by switching to Design view, and double-clicking an empty area of the page or using the Properties window.)

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<script runat="server">
   2:   protected void Page_Load(object sender, EventArgs e)
   3:   {
   4:     // retrieve the product ID from the query string
   5:     string productId = Request.QueryString["ProductID"];
   7:     // use productId to customize page contents
   8:     if (productId != null)
   9:     {
  10:       // set the page title
  11:       this.Title += ": Product " + productId;
  13:       // display product details
  14:       message.Text =
  15:         String.Format("You selected product #{0}. Good choice!",
  16:                       productId);
  17:     }
  18:     else
  19:     {
  20:       // display product details
  21:       message.Text = "Please select a product from our catalog.";
  22:     }
  24:   }

  1. Test your Web Form by loading http://seoasp/Product.aspx?ProductID=3. The result should resemble Figure 3.
  2. Let's now write the rewriting rule. Open the Program Files/Helicon/ISAPI_Rewrite/httpd.ini file (you can find a shortcut to this file in Programs), and add the following highlighted lines to the file. Note the file is read-only by default. If you use Notepad to edit it, you'll need to make it writable first.


# Translate /my-super.product.html to /Product.aspx?ProductID=123
RewriteRule ^/my-super-product\.html$ /Product.aspx?ProductID=123

  1. Switch back to your browser again, and this time load http://seoasp/my-super-product.html.


Technorati Tags:

Enabling Internet Explorer for Debugging ASP.NET AJAX


Microsoft's ASP.NET AJAX framework provides a solid foundation for building efficient and high performance Web-based applications that can enhance the overall end user experience. No matter how good a development platform is, however, bugs and other issues can be introduced by developers and triggered by end users. Knowing how to quickly debug ASP.NET AJAX applications can greatly increase your productivity as a developer and reduce the amount of frustration experienced while tracking down issues.

There are many tools available to you as an ASP.NET AJAX developer to efficiently debug and test your applications. For example there is debug functionality available in the ASP.NET AJAX script library that can be used to make assertions and perform tracing operations. There are several tools to intercept and view request and response messages, to more easily track down data issues and monitor AJAX request and response message sizes. This article looks at several ways to use Internet Explorer and Visual Studio to debug JavaScript. And there are also several different debugging techniques available in Firefox that can simplify the process of debugging ASP.NET AJAX applications.

Debugging JavaScript has proven to be somewhat of a challenge and has resulted in many developers resorting to "alert style" debugging to better understand how an application is working. Fortunately, Internet Explorer 6 or higher includes integrated debugging functionality that can be used to start a debug session and step through ASP.NET AJAX code with a debugging tool such as Visual Studio .NET 2005 or Microsoft's Script Debugger, as shown in the following sections. Learning how to leverage Internet Explorer debugging features can enhance your productivity and significantly minimize the amount of time you spend hunting down bugs and other issues.

The debug capabilities in Internet Explorer 6 or higher are disabled by default but can be turned on by going to Tools-->Internet Options-->Advanced. The Advanced tab defines two items that need to be unchecked (a check means you can't debug):

Also, check the "Display a notification about every script error" checkbox below these items so that you're notified as errors occur in a page. If this box isn't checked, an icon will appear in the lower-left corner of the browser; unless you click, it you may miss noting that a client-side error occurred. A side-effect of checking this checkbox is that you'll find that many other Web sites have errors as you browse to them, so you may want to leave it unchecked when you're not debugging your own applications.

Figure 1 shows what the Internet Explorer Advanced settings should look like to enable debugging.

Once debugging is enabled in Internet Explorer, an ASP.NET AJAX page can be debugged using several techniques. The following sections walk you through the options.

Debugging with Internet Explorer and Visual Studio .NET 2005

You can start a debug session several different ways. One of the easiest ways is to use the built-in script debugging capabilities of Internet Explorer. To start a debug session for an ASP.NET AJAX page, navigate to the page that you'd like to debug and select View-->Script Debugger from the Internet Explorer menu (see Figure 2). For this to work, you must enable Internet Explorer for debugging as described in the previous section.

You'll be presented with two different options, Open and Break at Next Statement, as shown in Figure 2. If you select Open, you'll be prompted to start using Visual Studio .NET as the debugger, as shown in Figure 3. If Visual Studio .NET is already open, you can begin debugging, or you can choose to start a new instance of Visual Studio .NET to use for debugging. If you select Break at Next Statement, nothing will happen until an action is performed that causes script within the page (or script referenced by the page) to execute. Once script code is executed in Internet Explorer, you'll be prompted to use the Visual Studio .NET Just-In-Time debugger.

Once Visual Studio .NET is open and available for debugging, you won't be able set a breakpoint if the script is embedded within the page. Instead, you'll see a message at the bottom of the Visual Studio .NET status bar that states "This is not a valid location for a breakpoint" when you try to set the breakpoint. There are several ways to solve this problem. First, you can add the JavaScript "debugger" statement directly into the code where you'd like to start a debug session, which will force a breakpoint to occur at runtime at that location in your code. However, ASP.NET AJAX's Sys.Debug class is designed for this purpose and is a more appropriate choice for debugging AJAX applications. You can call the Sys.Debug class's fail function to trigger the debugger when a specific line of code is hit.

The function accepts only one parameter that represents the reason for the failure. Listing 1 shows an example of using the function to break into a debug session right before songs are added into an Album object.

Listing 1

var album = new Wrox.ASPAJAX.Samples.Album();
album.set_title("Sam's Town");
album.set_artist("The Killers");
//Force the debugger to appear"Debug song additions");

var album = new Wrox.ASPAJAX.Samples.Album();
album.set_title("Sam's Town");
album.set_artist("The Killers");
//Force the debugger to appear"Debug song additions");


It's helpful to call to trigger a debug session when a line of JavaScript code is executed, but you must remember to remove all these calls before moving an application to a production environment, because it will always trigger the debugger when debugging is enabled in Internet Explorer. You can have two versions of your script (Microsoft does this with its debug and release scripts) and set the appropriate ScriptMode on the ScriptManager to determine which script is loaded at runtimeruntime (as discussed in Chapter 9 "Testing and Debugging ASP.NET AJAX Applications," of Professional ASP.NET 2.0 AJAX (Wrox, 2007, ISBN: 978-0-470-10962-5)). Although this means that your code is duplicated, the release script can have all whitespace characters stripped out of it to minimize its size, while the debug script can provide an easy-to-read script that contains the necessary calls to the Sys.Debug class for debugging, tracing, assertions and other operations.

Another option for triggering the debugger when the script is embedded in the page is to move all of the JavaScript code in the page into its own script file, instead of including it directly in the .aspx page. In this case, a separate file with an extension of .js is referenced by the page to be loaded separately at runtime, instead of being sent down to the browser along with the HTML markup. After you've done this you can set a breakpoint in the external script file. Figure 4 shows an example of JavaScript in a file named Listing9-12.js (available in the code download for the book, Professional ASP.NET AJAX (Wrox, 2007, ISBN: 978-0-470-10962-5), that has a breakpoint successfully set.

Figure 4

As you step through the code by pressing F11 (step into) or F10 (step over), you may be prompted to select the location of dynamically loaded script files needed by ASP.NET AJAX, or you may encounter an error that states "There is no source code available for the current location." This occurs when you try to step into dynamically generated script code that was loaded using the ScriptResource.axd and WebResource.axd HTTP handlers, so in this case, there isn't a separate physical file that Visual Studio can walk through. Although this problem can be frustrating at first, a simple tool that's already part of Visual Studio .NET can alleviate this problem.

Visual Studio .NET 2005 SP1 helps resolve this issue: however, knowing how to deal with the error if it arises is still helpful.

Visual Studio .NET 2005 includes a very functional tool called the Script Explorer that can be used to navigate through scripts within a page. The Script Explorer can be used to load dynamic scripts in the editor so that you can step into them easily using the debugger and avoid the dreaded "There is no source code available for the current location" error. If you are prompted to load a script file, simply cancel the dialog box (or if you receive the aforementioned error, click OK). Select Debug-->Windows-->Script Explorer (or press Ctrl+Alt+N) to view the Script Explorer window. Double-click the page currently being debugged to open it in the editor, and then double-click all of the other script files shown. This will open all of the files referenced by the page in Visual Studio .NET so that the debugger can access the necessary source code to allow for a rich debugging experience.

Figure 5 shows an example of the Script Explorer and the script files used in an ASP.NET AJAX-enabled page named Listing9-12.aspx (also available in the code download for the book, Professional ASP.NET AJAX).

Figure 5

Stepping through code during a debug session, you may notice that as you mouse over JavaScript variables you don't see any information or data like you do when debugging VB.NET or C# code. While you can typically use the Autos, Locals, Watch, or Immediate windows to access the variable data, you can also try highlighting the variable with the cursor and then hovering over the highlighted text with the cursor to see the data contained within the variable. This trick doesn't work in every situation but is a good one to keep in mind.

You can also start a debug session directly in Visual Studio .NET 2005, much as you would when debugging VB.NET or C# code within an ASP.NET page. First, right-click the page you'd like to debug in the Solution Explorer and select Set As Start Page from the menu. Then press F5 or click the green play button (the button with the green arrow on it) on the debug toolbar to start Internet Explorer and display the page. Set your breakpoints in the separate script files and then trigger the breakpoints by performing the action you'd like to debug in the browser.

As you step through code, you have full access to standard debug windows such as the Autos, Locals, Watch, and Immediate, as shown in Figure 6. By using these windows, you can quickly access variable data and drill down into your applications to see what is happening internally.

Although this section focuses on debugging features in Visual Studio .NET 2005, Visual Web Developer 2005 Express also has integrated debugging features that can be used to debug ASP.NET AJAX applications. While not as full-featured as the Visual Studio .NET 2005 debugger, it does have support for the Script Explorer, Locals, and Watch windows as well as several others.

Debugging with Internet Explorer and the Microsoft Script Debugger

In cases where you don't have access to Visual Studio .NET 2005 but need to debug ASP.NET AJAX pages and associated scripts, the Microsoft Script Debugger can be used to view and debug scripts and step through code line by line. The Script Debugger has been around for several years as a stand-alone product that can run on a variety of Microsoft operating systems, including Windows NT 4, Windows 2000, Windows Server 2003, Windows XP, and Windows Vista. It can be downloaded from (this URL is, of course, subject to change).

Once installed, the Script Debugger is automatically triggered when you select View-->Script Debugger-->Open (or Break at Next Statement) from the Internet Explorer menu. While the Script Debugger isn't as robust as the debugger built into Visual Studio .NET 2005, it is very functional and can help identify problems encountered in ASP.NET AJAX applications. Figure 7 shows what the Script Debugger looks like in action.

You can view all of the scripts used in the page through the Running Documents window, and you can set and remove breakpoints by placing the cursor on the line where you'd like to set (or remove) a breakpoint and then selecting the appropriate icon on the toolbar. The hand icon sets breakpoints, and the hand with a red "X" over it removes breakpoints. Scripts that are dynamically loaded in the page through ScriptResource.axd and WebResource.axd don't present a problem and are directly accessible to step into without any extra effort on your part.

Once the Script Debugger is started, you can step through code by pressing F8, step over code by pressing Shift+F8, or step out of code by pressing Ctrl+Shift+F8. Alternatively, you can select the appropriate icons on the toolbar to step through the code. As you step through code, you can view variables and their values by using the Command Window. Type the variable name or object function that you want to call, and it will be displayed.

Figure 8 shows an example of the windows available in the Script Debugger.

While you can run Visual Studio .NET 2005 and the Microsoft Script Debugger on the same machine, if you uninstall the Script Debugger, you may notice that the Script Debugger menu entry no longer appears in Internet Explorer or that Visual Studio .NET doesn't handle calls to This can be fixed by performing a repair on the Visual Studio .NET installation.