:::: MENU ::::

Thursday, August 27, 2009

Introduction
The .NET Framework is big. Really big. The System.Web assembly, which contains the guts of ASP.NET, is comprised of nearly 2,000 types, over 23,000 methods, and more than 12,500 properties. And that's not counting any of the functionality added to ASP.NET since version 2.0. ASP.NET AJAX, the ListView control, Dynamic Data, URL routing, and other features add hundreds of new types and thousands of new methods and properties.

Given the size and scope of the .NET Framework and ASP.NET even there are certain to be dark corners for even the most experienced developers. There are certain classes, methods, and properties in the .NET Framework that every ASP.NET developer is intimately familiar with: the Request.QueryString collection; the Session object; Page object properties like IsValid and IsPostBack. Yet even in these familiar classes there are very useful and very helpful properties, methods, and features that are less widely known. Heck, I've been building ASP.NET applications and writing about ASP.NET functionality and features full time since 2001, and once or twice a month I still stumble across an unknown feature or a helpful property or method buried in some dark corner of the framework.

This article lists four helpful methods, properties, and features in the .NET Framework that, in my experience, are not widely known to ASP.NET developers. Read on to see my list!


Typically, ASP.NET developers design, implement, and test their web applications from their personal computer, visiting the website through localhost. When the site is ready to be deployed it is moved to a different web server and the visitors are remote, reaching the website from a domain name like www.yoursite.com. Likewise, when developing the application it is not uncommon to have debugging enabled, which entails going to Web.config and setting the <compilation> element's debug attribute to true. However, this setting should always be set to false in production, as Scott Guthrie notes in his blog entry Don't run production ASP.NET Applications with debug="true" enabled.

Sometimes its helpful to know if the user visiting the website is coming from localhost or if debugging is enabled. For example, you might want to display debugging- or development-related information at the top of each web page, such as the time it took to execute the page or detailed information about the currently logged-in user. However, this information should not be shown to end users; rather, it should only be displayed if the user is visiting locally or if debugging is enabled.

The good news is that it's quite easy to determine whether a visitor has arrived at the site locally, thanks to the Response object's IsLocal property. Response.IsLocal returns True if the visitor is coming from localhost, False otherwise. To determine whether debugging is enabled, use the HttpContext object's IsDebuggingEnabled property. The code snippet below shows how to display a Panel (pnlDiagnosticInfo) only if the user is arriving from localhost and debugging is enabled.

// C#
if (Request.IsLocal && HttpContext.Current.IsDebuggingEnabled)
   pnlDiagnosticInfo.Visible = true;


' VB
If Request.IsLocal AndAlso HttpContext.Current.IsDebuggingEnabled Then
   pnlDiagnosticInfo.Visible = True
End If

Note that to use the HttpContext object's properties you need to first use HttpContext.Current to get a reference to the HttpContext object associated with this request.

2. The Panel Web Control's DefaultButton Property
A <form> in a web page can be submitted in a number of ways: a user can click a submit button; JavaScript can submit the form by calling its submit() function; or a user may hit Enter in a textbox. It's that last technique - hitting Enter in a textbox to submit the form - that can cause problems for web pages that contain multiple submit buttons. For example, an ASP.NET web application might have a master page that includes a search TextBox and Button Web control on every page. When the search Button on the master page is clicked, a postback ensues, the Button control's Click event handler runs, and the user is taken to a page that displays the results of their search query.

Now, imagine a content page that uses this master page and contains its own TextBox controls and a Button control titled "Insert." When the Insert Button is clicked, there is a postback and the Button's Click event handler fires, at which point a new record is added to the database, say.

What happens when we visit this content page in a browser, type some text into the search TextBox, and hit Enter? Hitting Enter causes the browser to submit the <form>, but what Button does the browser indicate as having been "clicked?" If the browser says that the Search Button was clicked, then that Button's Click event handler will fire on postback, but if the browser indicates that the Insert Button is clicked then that Button's Click event handler will fire. Typically, when hitting Enter in a TextBox the browser will report that the first submit button in the form has been clicked. The net result is that regardless of whether the focus was in the Search TextBox or in one of the TextBox controls in the content page, the same Button will report as being "clicked" when the user hits the Enter key. What we want is for the browser to report that the Search Button was "clicked" when the user hits Enter in the search TextBox, and for the browser to report that the Insert Button was "clicked" when the user hits Enter from one of the TextBoxes in the content page. (For a more in-depth discussion of this problem, see Two Common Pitfalls When Submitting a Web Form Using the Enter Key.)

This conundrum can be fixed by placing the search TextBox and Button inside a Panel Web control and setting the Panel's DefaultButton property to the ID of the search Button Web control. The master page's markup would look something like:

<asp:Panel runat="server" ID="pnlSearch" DefaultButton="btnSearch" ...>
   Search: <asp:TextBox runat="server" ID="txtSearch" ... />
   <asp:Button runat="server" ID="btnSearch" Text="Search" ... />
</asp:Panel>

Setting the Panel's DefaultButton property causes the Panel to render with additional JavaScript that is triggered whenever the user presses a key when focused within the Panel. The JavaScript function monitors these keystrokes, and when the Enter key is pressed the code submits the <form>, reporting that the associated Button control was clicked.

For more information on this property, check out my blog entry, The DefaultButton Property - News To Me!

3. Creating Fully Qualified URLs Using Request.Url.GetLeftPart(UriPartial.Authority)
The Request object includes a number of properties for determining path information. For example, the Request object's PhysicalPath property returns the physical path to the currently executing page (e.g., D:\Websites\DemoApp\Tutorial01\MyPage.aspx) whereas the Url property returns the fully qualified URL of the currently requested page (e.g., http://www.yourserver.com/Tutorial01/MyPage.aspx). But what if you want to build a fully qualified URL from scratch?

This is a common challenge when writing code that sends an e-mail that includes a URL back to the website. For example, if your site supports user accounts you might want to send newly registered users an e-mail message welcoming them to the site. You might want to include a URL to the login page in this e-mail. If you know the fully qualified URL of the login page - such as http://www.yourserver.com/Login.aspx - you can hard-code it into the e-mail's body. But what if you haven't settled on a domain name yet? Or what if the software you are developing will be used by various clients, each who have their own domain names? In this case you need to generate a fully qualified URL programmatically. You know the file name of the login page (~/Login.aspx), but you need to write code to generate the left-hand portion, http://www.yourserver.com/, or perhaps http://www.yourserver.com/MyApp/, if the application is rooted at a virtual directory.

Rick Strahl shows how this information can be pieced together from various variables in the ServerVariables collection, but there's an even easier way using the Request object's Url property's GetLeftPart method. In short, the GetLeftPart method returns the specified portion of the URL. The UriPartial.Authority enumeration value passed into this method instructs GetLeftPart method to return the protocol (http:// or https://) along with the domain name and port number (if present). For example, if the requested page's URL is http://www.yourserver.com:8080/Tutorial01/MyPage.aspx, then calling Request.Url.GetLeftPart(UriPartial.Authority) returns the string http://www.yourserver.com:8080.

The following code snippet shows how to build up a fully qualified URL for the login page using Request.Url.GetLeftPart(UriPartial.Authority):

// C#
string loginUrl = Request.Url.GetLeftPart(UriPartial.Authority) +
                  Page.ResolveUrl("~/Login.aspx");

' VB
Dim loginUrl As String = Request.Url.GetLeftPart(UriPartial.Authority) & _
                         Page.ResolveUrl("~/Login.aspx")

The call to Page.ResolveUrl("~/Login.aspx") generates a rooted path to the login page, such as /Tutorial01/Login.aspx. The net effect is that loginUrl is assigned the fully qualified path to the login page, http://www.yourserver.com:8080/Tutorial01/Login.aspx.

4. Taking An ASP.NET Web Application Offline
When performing maintenance on a production website, pushing up new or modified code/web pages, or taking any other sort of action that may disrupt a user's experience, it is a good idea to take the application offline and replace it with a single web page that explains that the website is currently unavailable. IIS, Microsoft's production-grade web server, includes an option to redirect all incoming traffic to a specific URL. This includes requests for any sort of content - ASP.NET pages, static HTML pages, images, CSS files, JavaScript files... whatever.

ASP.NET provides its own mechanism for taking an application offline. In short, if you upload a file to your website named App_Offline.htm the ASP.NET engine will automatically display the contents of the App_Offline.htm for any request to an ASP.NET page. By merely uploading such a file you effectively take your site offline and can display a nice-looking, informative message to visitors explaining why the site is offline, when you expect it to be back up, and so on. To bring the site back up, simply delete (or rename) the App_Offline.htm file.

The main benefit of App_Offline.htm over configuring IIS to redirect all traffic to a specified URL is that App_Offline.htm can be used in virtually any environment, whereas configuring IIS requires access and permission to modify the web server's settings. Typically, such access is not granted in a shared hosting environment, making the App_Offline.htm approach more amenable for such situations.

An earlier article on 4Guys, Taking an ASP.NET Application Offline, shows how to configure IIS to redirect all requests to a static URL, examines alternative approaches to taking an ASP.NET application offline, and discusses App_Offline.htm in more detail. It also includes a demo on how to programmatically create the App_Offline.htm file from a web page, thereby allowing a site to be taken offline from the web. (No need to FTP a file!)

Bear in mind that there are some subtleties that you must be aware of when using App_Offline.htm. As noted in Taking an ASP.NET Application Offline:

The ASP.NET runtime will not return an App_Offline.htm file if it exceeds 1 MB in size. Furthermore, if your App_Offline.htm file is too small (less than 512 bytes), Internet Explorer will display its "friendly 404 error page" rather than the content returned by App_Offline.htm (assuming friendly HTTP error pages are enabled in IE, which they are, by default).

Conclusion
Due to its size and scope, the .NET Framework has a lot of pigeonholes where useful functionality is tucked away. Even when working with the .NET Framework on a daily basis for years on end there are still spots that remain unexplored. This article shared four helpful bits of knowledge on ASP.NET that you may not have known about before. Is there a golden nugget or two in the .NET Framework that you use on a regular basis, but have found that your fellow developers are usually unaware of?