0% found this document useful (0 votes)
1K views

Error Handling in ASP

This document discusses error handling in ASP.NET. It recommends identifying where errors may occur and handling them gracefully using try-catch blocks. It describes different types of exceptions like SQLException and NullReferenceException. It also discusses using Option Strict and Option Explicit to prevent errors, and creating custom exceptions by deriving from ApplicationException.

Uploaded by

kagga1980
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1K views

Error Handling in ASP

This document discusses error handling in ASP.NET. It recommends identifying where errors may occur and handling them gracefully using try-catch blocks. It describes different types of exceptions like SQLException and NullReferenceException. It also discusses using Option Strict and Option Explicit to prevent errors, and creating custom exceptions by deriving from ApplicationException.

Uploaded by

kagga1980
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 116

Error Handling in ASP.NET...

In anything but the simplest of cases your application will contain errors. You should identify
where errors might be likely to occur and code to anticpate and handle them gracefully.

By: Chris Sully Date: March 30, 2003 Printer Friendly Version

Introduction

I came to the realisation a little time ago that I really wasn’t making the most of the error
handling facilities of ASP.NET. The sum of my ASP.Net error handling knowledge up until that
point was the new (to VB) Try … Catch … Finally construct at the page level. While I shall
examine this new addition there are more facilities at our disposal and this article shall share the
results of my recent investigations.

In anything but the simplest of cases your application WILL contain errors. You should identify
where errors might be likely to occur and code to anticipate and handle them gracefully.

The .NET Framework’s Common Language Runtime (CLR) implements exception handling as
one of its fundamental features. As you might expect due to the language independence of the
framework you can also write error handling in VB.NET that can handle errors in C# code, for
example. The exception object thrown is of the same primitive type (System.Exception).

Options … Options (preventing runtime errors)

If we can we should capture errors as early as possible as fewer will then make it through to the
runtime environment. VB.Net offers the Option Strict and Option Explicit statements to prevent
errors at design time.

Classic ASP programmers should be familiar with Option Explicit – it forces explicit declaration
of all variables at the module level. In addition when programming ASP.NET pages in VB.NET
when Option Explicit is enabled, you must declare all variables using Public, Private, Dim or
Redim.

The obvious mistake that Option Explicit captures is using the same variable name multiple
times within the same scope … a situation which is very likely to lead to runtime errors, if not
exceptions.

Thankfully, in ASP.NET Option Explicit is set to on by default. If for any reason you did need to
reset, the syntax is:

Option Explicit Off

at the top of a code module or


<%@ Page Explicit=”False”%>

in a web form.

Enabling Option Strict causes errors to be raised if you attempt a data type conversion that leads
to a loss in data. Thus, if this lost data is of potential importance to your application Option Strict
should be enabled. Option Strict is said to only allow ‘widening’ conversions, where the target
data type is able to accommodate a greater amount of data than that being converted from.

The syntax is as per Option Explicit.

Exceptions

What precisely is an exception? The exception class is a member of the System namespace and is
the base class for all exceptions. Its two sub-classes are the SystemException class and the
ApplicationException class.

The SystemException class defines the base class for all .NET predefined exceptions. One I
commonly encounter is the SQLException class, typically when I haven’t quite specified my
stored procedure parameters correctly in line with the stored procedure itself.

When an exception object is thrown that is derived from the System.Exception class you can
obtain information from it regarding the exception that occurred. For example, the following
properties are exposed:

HelpLink Gets or sets a link to the help file associated with this exception.
InnerException Gets the Exception instance that caused the current exception.
Message Gets a message that describes the current exception.
Source Gets or sets the name of the application or the object that causes the error.
Gets a string representation of the frames on the call stack at the time the current
StackTrace
exception was thrown.
TargetSite Gets the method that throws the current exception.

See the SDK documentation for more information.

The ApplicationException class allows you to define your own exceptions. It contains all the
same properties and methods as the SystemException class. We shall return to creating such
custom exceptions after examining the main error handling construct at our disposal: 'Try …
Catch … Finally'.

Structured and Unstructured Error Handling


Previous versions of VB had only unstructured error handling. This is the method of using a
single error handler within a method that catches all exceptions. It’s messy and limited. Briefly,
VB’s unstructured error handlers (still supported) are:

On Error GoTo line[or]label


On Error Resume Next
On Error GoTo 0
On Error GoTo -1

But forget about these as we now have new and improved C++ like structured exception
handling with the Try ... Catch … Finally construct, as follows:

Try
[ tryStatements ]
[ Catch [ exception [ As type ] ] [ When expression ]
[ catchStatements ] ]
[ Exit Try ]
...
[ Finally
[ finallyStatements ] ]
End Try

Thus we try to execute some code; if this code raises an exception the runtime will check to see
if the exception is handled by any of the Catch blocks in order. Finally we may execute some
cleanup code, as appropriate. Exit Try optionally allows us to break out of the construct and
continue executing code after End Try. When optionally allows specification of an additional
condition which must evaluate to true for the Catch block to be executed.

Here’s my code snippet for SQL server operations by way of a simple, and not particularly good
(see later comments), example:

Try

myConnection.open()
myCommand = new SQLCommand("USP_GENERIC_select_event_dates", myConnection)
myCommand.CommandType = CommandType.StoredProcedure

myCommand.Parameters.Add(New SQLParameter("@EventId",SQLDBType.int))
myCommand.Parameters("@EventId").value=EventId

objDataReader=myCommand.ExecuteReader()

Catch objError As Exception

'display error details


outError.InnerHtml = "<b>* Error while executing data command (ADMIN:
Select Event Dates)</b>.<br />" _
& objError.Message & "<br />" & objError.Source & _
". Please <a href='mailto:[email protected]'>e-mail us</a> providing
as much detail as possible including the error message, what page you were
viewing and what you were trying to achieve.<p /><p />"

Exit Function ' and stop execution

End Try

There are several problems with this code as far as best practice is concerned, the more general
of which I’ll leave to the reader to pick up from the following text, but in particular there should
be a Finally section which tidies up the database objects.

Note it is good form to have multiple Catch blocks to catch different types of possible
exceptions. The order of the Catch blocks affects the possible outcome … they are checked in
order.

You can also throw your own exceptions for the construct to deal with; or re-throw existing
exceptions so they are dealt with elsewhere. See the next section for a little more detail.

You could just have a Catch block that trapped general exceptions – exception type ‘exception’
(see above!). This is not recommended as it suggests a laziness to consider likely errors. The
initial catch blocks should be for possible specific errors with a general exception catch block as
a last resort if not covered by earlier blocks.

For example, if accessing SQLServer you know that a SQLException is possible. If you know an
object may return a null value and will cause an exception, you can handle it gracefully by
writing a specific catch statement for a NullReferenceException.

For you information here’s a list of the predefined exception types provided by the .NET
Runtime:

Exception type Base type Description Example


Base class for None (use a derived
Exception Object
all exceptions. class of this exception).
Base class for
all runtime- None (use a derived
SystemException Exception
generated class of this exception).
errors.
Thrown by the
runtime only Indexing an array
IndexOutOfRangeException SystemException when an array outside its valid range:
is indexed arr[arr.Length+1]
improperly.
NullReferenceException SystemException Thrown by the object o = null;
runtime only
when a null
o.ToString();
object is
referenced.
Calling
Thrown by
Enumerator.GetNext()
methods when
InvalidOperationException SystemException after removing an Item
in an invalid
from the underlying
state.
collection.
Base class for
None (use a derived
ArgumentException SystemException all argument
class of this exception).
exceptions.
Thrown by
methods that String s = null;
ArgumentNullException ArgumentException do not allow "Calculate".IndexOf
an argument to (s);
be null.
Thrown by
methods that
verify that String s = "string";
ArgumentOutOfRangeException ArgumentException
arguments are s.Chars[9];
in a given
range.
Base class for
exceptions
that occur or
None (use a derived
ExternalException SystemException are targeted at
class of this exception).
environments
outside the
runtime.
Exception
encapsulating
ComException ExternalException COM Used in COM interop.
HRESULT
information.
SEHException ExternalException Exception Used in unmanaged
encapsulating code interop.
Win32
structured
exception
handling
information.

Throwing Exceptions

As indicated earlier, not only can you react to raised exceptions, you can throw exceptions too
when needed. For example, you may wish to re-throw an exception after catching it and not
being able to recover from the exception. Your application-level error handling could then
redirect to an appropriate error page.

You may further wish to throw your own custom exceptions in reaction to error conditions in
your code.

The syntax is

Throw new [Exception]

Creating Custom Exceptions

As mentioned earlier, via the ApplicationException class you have the ability to create your own
exception types.

Here’s an example VB class to do just that:

Imports System
Imports System.Text

Namespace CustomExceptions

Public Class customException1: Inherits ApplicationException

Public Sub New()

MyBase.New("<H4>Custom Exception</H4><BR>")
Dim strBuild As New StringBuilder()
strBuild.Append("<p COLOR='RED'>")
strBuild.Append("For more information ")
strBuild.Append("please visit: ")
strBuild.Append("<a href='http://www.cymru-web.net/exceptions'>")
strBuild.Append("Cymru-Web.net</a></p>")
MyBase.HelpLink = strBuild.ToString()

End Sub

End Class

End Namespace

Looking at this code. On line 6 you see that to create a custom exception we must inherit from
the ApplicationException class. In the initialization code for the class we construct a new
ApplicationException object using a string (one of the overloaded constructors of
ApplicationException – see the .NET documentation for details of the others). We also set the
HelpLink property string for the exception – this is a user friendly message for presentation to
any client application.

The MyBase keyword behaves like an object variable referring to the base class of the current
instance of a class (ApplicationException). MyBase is commonly used to access base class
members that are overridden or shadowed in a derived class. In particular, MyBase.New is used
to explicitly call a base class constructor from a derived class constructor.

Next a small test client, written in VB.NET using Visual Studio.Net so we have both web form
and code behind files:

WebForm1.aspx:

<%@ Page Language="vb" AutoEventWireup="false" Codebehind="WebForm1.aspx.vb"


Inherits="article_error_handling.WebForm1"%>
<html>
<body>
</body>
</html>

WebForm1.aspx.vb

Imports article_error_handling.CustomExceptions

Public Class WebForm1

Inherits System.Web.UI.Page

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles MyBase.Load
Try
Throw New customException1()
Catch ex As customException1
Response.Write(ex.Message & " " & ex.HelpLink)
End Try
End Sub

End Class

This (admittedly simple) example you can extend to your own requirements.

Page Level Error Handling

Two facets:

1. Page redirection
2. Using the Page objects error event to capture exceptions
Taking each in turn:

Page redirection

Unforeseen errors can be trapped with the ErrorPage property of the Page object. This allows
definition of a redirection URL in case of unhandled exceptions. A second step is required to
enable such error trapping however – setting of the customErrors attribute of your web.config
file, as follows:

<configuration>
<system.web>
<customErrors mode="On">
</customErrors>
</system.web>
</configuration>

Then you’ll get your page level redirection rather than the page itself returning an error, so the
following would work:

<%@ Page ErrorPage="http://www.cymru-web.net/GenericError.htm" %>

A useful option in addition to ‘on’ and ‘off’ for the mode attribute of customErrors is
‘RemoteOnly’ as when specified redirection will only occur if the browser application is running
on a remote computer. This allows those with access to the local computer to continue to see the
actual errors raised.

Page Objects Error Event

The Page object has an error event that is fired when an unhandled exception occurs in the page.
It is not fired if the exception is handled in the code for the page. The relevant sub is Page_Error
which you can use in your page as illustrated by the following code snippet:

Sub Page_Error(sender as Object, e as EventArgs)

dim PageException as string = Server.GetLastError().ToString()


dim strBuild as new StringBuilder()
strBuild.Append("Exception!")
strBuild.Append(PageException)

Response.Write(strBuild.ToString())
Context.ClearError()

End Sub

As with page redirection this allows you to handle unexpected errors in a more user-friendly
fashion. We’ll return to explain some of the classes used in the snippet above when we look at a
similar scenario at the application level in the next section.

Application Level Error Handling


In reality you are more likely to use application level error handling rather than the page level
just introduced. The Application_Error event of the global.asax exists for this purpose.
Unsurprisingly, this is fired when an exception occurs in the corresponding web application.

In the global.asx you code against the event as follows:

Sub Application_Error(sender as Object, e as EventArgs)


'Do Something
End Sub

Unfortunately the EventArgs in this instance are unlikely to be sufficiently informative but there
are alternative avenues including that introduced in the code of the last section – the
HttpServerUtility.GetLastError method which returns a reference to the last error thrown in the
application. This can be used as follows:

Sub Application_Error(sender as Object, e as EventArgs)

dim LastException as string = Server.GetLastError().ToString()

Context.ClearError()

Response.Write(LastException)

End Sub

Note that the ClearError method of the Context class clears all exceptions from the current
request – if you don’t clear it the normal exception processing and consequent presentation will
still occur.

Alternatively there is the HttpContext’s class Error property which returns a reference to the first
exception thrown for the current HTTP request/ response. An example:

Sub Application_Error(sender as Object, e as EventArgs)

dim LastException as string = Context.Error.ToString()

Context.ClearError()

Response.Redirect("CustomErrors.aspx?Err=" &
Server.UrlEncode(LastException))

End Sub

This illustrates one method for handling application errors – redirection to a custom error page
which can then customise the output to the user dependent on the actual error received.

Finally, we also have the ability to implement an application wide error page redirect, via the
customErrors section of web.config already introduced, using the defaultRedirect property:

<configuration>
<system.web>
<customErrors mode="on" defaultRedirect="customerrors.aspx?
err=Unspecified">
<error statusCode="404" redirect="customerrors.aspx?err=File+Not+Found"/>
</customErrors>
</system.web>
</configuration>

Note this also demonstrates customised redirection via the error attribute. The HttpStatusCode
enumeration holds the possible values of statusCode. This is too long a list to present here - see
the SDK documentation.

Conclusion

I hope this has provided a useful introduction to the error handling facilities of ASP.NET. I
further hope you’ll now go away and produce better code that makes use of these facilities! In
summary:

• Trap possible errors at design time via Option Explicit and Option Strict.
• Consider in detail the possible errors that could occur in your application.
• Use the Try … Catch … Finally construct to trap these errors at the page level and
elsewhere.
• It is generally considered poor programming practice to use exceptions for anything
except unusual but anticipated problems that are beyond your programmatic control (such
as losing a network connection). Exceptions should not be used to handle programming
bugs!
• Use application level exception handling (and perhaps also Page level) to trap foreseen
and unforeseen errors in a user friendly way.

ASP.NET
Complete Example for Error Handlers

The example consists of the following files:

• Web.config
• Global.asax
• Default.aspx
• ExceptionUtility (to be put in the App_Code folder)
• GenericErrorPage.aspx
• HttpErrorPage.aspx
• Http404ErrorPage.aspx
• DefaultRedirectErrorPage.aspx

Web.config
The following example shows the Web.config file. The customErrors section specifies how to
handle errors that occur with file types that are mapped to ASP.NET, such as .aspx, .asmx, and
.ashx files. (In IIS 6.0 and in IIS 7.0 in classic mode, static content files such as .html and .jpg
files are not mapped to ASP.NET.)

The settings in the example customErrors section cause any unhandled HTTP 404 (file not
found) errors to be directed to the Http404ErrorPage.aspx file. These HTTP 404 errors would
occur if a request were made for an .aspx file, .asmx file, and so on and if the requested file did
not exist. All other unhandled errors in ASP.NET files are directed to the
DefaultRedirectErrorPage.aspx file.

If static content files are not handled by ASP.NET, a request for a nonexistent .html or .jpg file
does not cause a redirect to the Http404ErrorPage.aspx file. If you want ASP.NET to handle
requests for all file types, you can configure IIS to map file-name extensions to ASP.NET.

Note:
In the example, the mode attribute is set to "On" so that you can error messages when you run the
example in Visual Studio. In a production environment, this setting would normally be
"RemoteOnly". ASP.NET then renders error pages to external users. If a request is made on the
server computer (localhost), ASP.NET renders a page with detailed error information.
None
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<compilation debug="true" />

<!-- Turn on Custom Errors -->


<customErrors mode="On"
defaultRedirect="DefaultRedirectErrorPage.aspx">
<error statusCode="404" redirect="Http404ErrorPage.aspx"/>
</customErrors>

</system.web>
</configuration>

Global.asax

The following example shows the Global.asax file

Security Note:
Never set the mode attribute in the customErrors element to "Off" in the Web.config file if you
have not created an Application_Error handler in the Global.asax file. If the mode is set to "Off,"
potentially compromising information about your Web site can be exposed to anyone who can
cause an error to occur on your site.
Visual Basic
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
' Code that runs when an unhandled error occurs
' Get the exception object.
Dim exc As Exception = Server.GetLastError

' Handle HTTP errors (avoid trapping HttpUnhandledException


' which is generated when a non-HTTP exception
' such as the ones generated by buttons 1-3 in
' Default.aspx is not handled at the page level).
If (exc.GetType Is GetType(HttpException)) Then
' The Complete Error Handling Example generates
' some errors using URLs with "NoCatch" in them;
' ignore these here to simulate what would happen
' if a global.asax handler were not implemented.
If exc.Message.Contains("NoCatch") Then
Return
End If

'Redirect HTTP errors to HttpError page


Server.Transfer("HttpErrorPage.aspx")
End If

' For other kinds of errors give the user some information
' but stay on the default page
Response.Write("<h2>Global Page Error</h2>" & vbLf)
Response.Write("<p>" & exc.Message + "</p>" & vbLf)
Response.Write(("Return to the <a href='Default.aspx'>" _
& "Default Page</a>" & vbLf))

' Log the exception and notify system operators


ExceptionUtility.LogException(exc, "DefaultPage")
ExceptionUtility.NotifySystemOps(exc)

' Clear the error from the server


Server.ClearError()
End Sub
C#
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs

// Get the exception object.


Exception exc = Server.GetLastError();

// Handle HTTP errors


if (exc.GetType() == typeof(HttpException))
{
// The Complete Error Handling Example generates
// some errors using URLs with "NoCatch" in them;
// ignore these here to simulate what would happen
// if a global.asax handler were not implemented.
if (exc.Message.Contains("NoCatch"))
return;

//Redirect HTTP errors to HttpError page


Server.Transfer("HttpErrorPage.aspx");
}
// For other kinds of errors give the user some information
// but stay on the default page
Response.Write("<h2>Global Page Error</h2>\n");
Response.Write(
"<p>" + exc.Message + "</p>\n");
Response.Write("Return to the <a href='Default.aspx'>" +
"Default Page</a>\n");

// Log the exception and notify system operators


ExceptionUtility.LogException(exc, "DefaultPage");
ExceptionUtility.NotifySystemOps(exc);

// Clear the error from the server


Server.ClearError();
}

ExceptionUtility

The following example shows the ExceptionUtility file. Error logs might be directed to the
computer's ErrorLog file, or, if the computer is part of a Web farm, the error log might be
recorded in a globally available text file, or even a database. You might also need to immediately
notify system administrators of a problem.

The ExceptionUtility class in the example has two static methods: one to log the exception, and
one to notify system administrators. How those methods are implemented in your code depends
on the needs of your organization. For this example, you must grant write permissions to the
ASP.NET worker process account (by default, this is NETWORK SERVICE) for the App_Data
folder to enable the application to write to the error log.

Visual Basic
Imports System
Imports System.IO
Imports System.Web

' Create our own utility for exceptions


Public NotInheritable Class ExceptionUtility

' All methods are static, so this can be private


Private Sub New()
MyBase.New()
End Sub

' Log an Exception


Public Shared Sub LogException(ByVal exc As Exception, ByVal source As
String)
' Include enterprise logic for logging exceptions
' Get the absolute path to the log file
Dim logFile = "App_Data/ErrorLog.txt"
logFile = HttpContext.Current.Server.MapPath(logFile)

' Open the log file for append and write the log
Dim sw = New StreamWriter(logFile, True)
sw.WriteLine("**** " & DateTime.Now & " ****")
If exc.InnerException IsNot Nothing Then
sw.Write("Inner Exception Type: ")
sw.WriteLine(exc.InnerException.GetType.ToString)
sw.Write("Inner Exception: ")
sw.WriteLine(exc.InnerException.Message)
sw.Write("Inner Source: ")
sw.WriteLine(exc.InnerException.Source)
If exc.InnerException.StackTrace IsNot Nothing Then
sw.WriteLine("Inner Stack Trace: ")
sw.WriteLine(exc.InnerException.StackTrace)
End If
End If
sw.Write("Exception Type: ")
sw.WriteLine(exc.GetType.ToString)
sw.WriteLine("Exception: " & exc.Message)
sw.WriteLine("Source: " & source)
If exc.StackTrace IsNot Nothing Then
sw.WriteLine("Stack Trace: ")
sw.WriteLine(exc.StackTrace)
End If
sw.WriteLine()
sw.Close()
End Sub

' Notify System Operators about an exception


Public Shared Sub NotifySystemOps(ByVal exc As Exception)
' Include code for notifying IT system operators
End Sub
End Class
C#
using System;
using System.IO;
using System.Web;

// Create our own utility for exceptions


public sealed class ExceptionUtility
{
// All methods are static, so this can be private
private ExceptionUtility()
{ }

// Log an Exception
public static void LogException(Exception exc, string source)
{
// Include enterprise logic for logging exceptions
// Get the absolute path to the log file
string logFile = "App_Data/ErrorLog.txt";
logFile = HttpContext.Current.Server.MapPath(logFile);

// Open the log file for append and write the log
StreamWriter sw = new StreamWriter(logFile, true);
sw.WriteLine("********** {0} **********", DateTime.Now);
if (exc.InnerException != null)
{
sw.Write("Inner Exception Type: ");
sw.WriteLine(exc.InnerException.GetType().ToString());
sw.Write("Inner Exception: ");
sw.WriteLine(exc.InnerException.Message);
sw.Write("Inner Source: ");
sw.WriteLine(exc.InnerException.Source);
if (exc.InnerException.StackTrace != null)
{
sw.WriteLine("Inner Stack Trace: ");
sw.WriteLine(exc.InnerException.StackTrace);
}
}
sw.Write("Exception Type: ");
sw.WriteLine(exc.GetType().ToString());
sw.WriteLine("Exception: " + exc.Message);
sw.WriteLine("Source: " + source);
sw.WriteLine("Stack Trace: ");
if (exc.StackTrace != null)
{
sw.WriteLine(exc.StackTrace);
sw.WriteLine();
}
sw.Close();
}

// Notify System Operators about an exception


public static void NotifySystemOps(Exception exc)
{
// Include code for notifying IT system operators
}
}

Default.aspx

The following example shows the Default.aspx page. This file provides several buttons, each of
which raises a different exception. The Page_Error handler on the page displays an error page
and logs some of these errors. Unhandled errors are passed to the Application_Error handler in
the Global.asax file. The Application_Error handler displays an error page and logs some of the
remaining errors. Any errors that are still not handled are directed to the page indicated by the
customErrors section of Web.config file.

Visual Basic
<%@ Page Language="VB" %>

<script runat="server">
Protected Sub Submit_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim arg As String = CType(sender, Button).CommandArgument
Select Case (arg)
Case "1"
' Exception handled on the Generic Error Page
Throw New InvalidOperationException("Button 1 was clicked")
Exit Select
Case "2"
' Exception handled on the current page
Throw New ArgumentOutOfRangeException("Button 2 was clicked")
Exit Select
Case "3"
' Exception handled by Application_Error
Throw New Exception("Button 3 was clicked")
Exit Select
Case "4"
' Exception handled on the Http 404 Error Page
Response.Redirect("NonexistentPage.aspx")
Exit Select
Case "5"
' Exception handled on the Http Error Page
Response.Redirect("NonexistentPage-NoCatch.aspx")
Exit Select
Case "6"
' Exception handled on the Default Redirect Error Page
Response.Redirect("Global-NoCatch.asax")
Exit Select
End Select
End Sub

Private Sub Page_Error(ByVal sender As Object, ByVal e As EventArgs)


' Get last error from the server
Dim exc As Exception = Server.GetLastError

' Handle exceptions generated by Button 1


If TypeOf exc Is InvalidOperationException Then
' Pass the error on to the Generic Error page
Server.Transfer("GenericErrorPage.aspx", True)

' Handle exceptions generated by Button 2


ElseIf TypeOf exc Is ArgumentOutOfRangeException Then
' Give the user some information, but
' stay on the default page
Response.Write("<h2>Default Page Error</h2>" & vbLf)
Response.Write(("<p>Provide as much information here as is " _
& "appropriate to show to the client.</p>" & vbLf))
Response.Write(("Return to the <a href='Default.aspx'>" _
& "Default Page</a>" & vbLf))
' Log the exception and notify system operators
ExceptionUtility.LogException(exc, "DefaultPage")
ExceptionUtility.NotifySystemOps(exc)
' Clear the error from the server
Server.ClearError()
Else
' Pass the error on to the default global handler
End If
End Sub

</script>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head id="Head1" runat="server">
<title>Exception Handler Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>
Default Page</h2>
<p>
Click this button to create an InvalidOperationException.<br />
Page_Error will catch this and redirect to
GenericErrorPage.aspx.<br />
<asp:Button ID="Submit1" runat="server"
CommandArgument="1" OnClick="Submit_Click"
Text="Button 1" />
</p>
<p>
Click this button to create an ArgumentOutOfRangeException.<br />
Page_Error will catch this and handle the error.<br />
<asp:Button ID="Submit2" runat="server"
CommandArgument="2" OnClick="Submit_Click"
Text="Button 2" />
</p>
<p>
Click this button to create a generic Exception.<br />
Application_Error will catch this and handle the error.<br />
<asp:Button ID="Submit3" runat="server"
CommandArgument="3" OnClick="Submit_Click"
Text="Button 3" />
</p>
<p>
Click this button to create an HTTP 404 (not found) error.<br />
Application_Error will catch this
and redirect to HttpErrorPage.aspx.<br />
<asp:Button ID="Submit4" runat="server"
CommandArgument="4" OnClick="Submit_Click"
Text="Button 4" />
</p>
<p>
Click this button to create an HTTP 404 (not found) error.<br />
Application_Error will catch this but will not take any action on it,
and ASP.NET will redirect to Http404ErrorPage.aspx.
The original exception object will not be available.<br />
<asp:Button ID="Submit5" runat="server"
CommandArgument="5" OnClick="Submit_Click"
Text="Button 5" />
</p>
<p>
Click this button to create an HTTP 403 (forbidden) error.<br />
Application_Error will catch this but will not take any action on it,
and ASP.NET will redirect to DefaultRedirectErrorPage.aspx.
The original exception object will not be available.<br />
<asp:Button ID="Button1" runat="server"
CommandArgument="6" OnClick="Submit_Click"
Text="Button 6" />
</p>
</div>
</form>
</body>
</html>
C#
<%@ Page Language="C#" %>

<script runat="server">
protected void Submit_Click(object sender, EventArgs e)
{
string arg = ((Button)sender).CommandArgument;

switch (arg)
{
case "1":
{
// Exception handled on the Generic Error Page
throw new InvalidOperationException("Button 1 was clicked");
break;
}
case "2":
{
// Exception handled on the current page
throw new ArgumentOutOfRangeException("Button 2 was clicked");
break;
}
case "3":
{
// Exception handled by Application_Error
throw new Exception("Button 3 was clicked");
break;
}
case "4":
{
// Exception handled on the Http 404 Error Page
Response.Redirect("NonexistentPage.aspx");
break;
}
case "5":
{
// Exception handled on the Http Error Page
Response.Redirect("NonexistentPage-NoCatch.aspx");
break;
}
case "6":
{
// Exception handled on the Generic Http Error Page
Response.Redirect("Global-NoCatch.asax");
break;
}
}
}
private void Page_Error(object sender, EventArgs e)
{
// Get last error from the server
Exception exc = Server.GetLastError();

// Handle exceptions generated by Button 1


if (exc is InvalidOperationException)
{
// Pass the error on to the Generic Error page
Server.Transfer("GenericErrorPage.aspx", true);
}

// Handle exceptions generated by Button 2


else if (exc is ArgumentOutOfRangeException)
{
// Give the user some information, but
// stay on the default page
Response.Write("<h2>Default Page Error</h2>\n");
Response.Write("<p>Provide as much information here as is " +
"appropriate to show to the client.</p>\n");
Response.Write("Return to the <a href='Default.aspx'>" +
"Default Page</a>\n");

// Log the exception and notify system operators


ExceptionUtility.LogException(exc, "DefaultPage");
ExceptionUtility.NotifySystemOps(exc);

// Clear the error from the server


Server.ClearError();
}
else
{
// Pass the error on to the default global handler
}
}
</script>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head id="Head1" runat="server">
<title>Exception Handler Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>
Default Page</h2>
<p>
Click this button to create an InvalidOperationException.<br />
Page_Error will catch this and redirect to
GenericErrorPage.aspx.<br />
<asp:Button ID="Submit1" runat="server"
CommandArgument="1" OnClick="Submit_Click"
Text="Button 1" />
</p>
<p>
Click this button to create an ArgumentOutOfRangeException.<br />
Page_Error will catch this and handle the error.<br />
<asp:Button ID="Submit2" runat="server"
CommandArgument="2" OnClick="Submit_Click"
Text="Button 2" />
</p>
<p>
Click this button to create a generic Exception.<br />
Application_Error will catch this and handle the error.<br />
<asp:Button ID="Submit3" runat="server"
CommandArgument="3" OnClick="Submit_Click"
Text="Button 3" />
</p>
<p>
Click this button to create an HTTP 404 (not found) error.<br />
Application_Error will catch this
and redirect to HttpErrorPage.aspx.<br />
<asp:Button ID="Submit4" runat="server"
CommandArgument="4" OnClick="Submit_Click"
Text="Button 4" />
</p>
<p>
Click this button to create an HTTP 404 (not found) error.<br />
Application_Error will catch this
but will not take any action on it, and ASP.NET
will redirect to Http404ErrorPage.aspx.
The original exception object will not be
available.<br />
<asp:Button ID="Submit5" runat="server"
CommandArgument="5" OnClick="Submit_Click"
Text="Button 5" />
</p>
<p>
Click this button to create an HTTP 403 (forbidden) error.<br />
Application_Error will catch this
but will not take any action on it, and ASP.NET
will redirect to DefaultRedirectErrorPage.aspx.
The original exception object will not
be available.<br />
<asp:Button ID="Button1" runat="server"
CommandArgument="6" OnClick="Submit_Click"
Text="Button 6" />
</p>
</div>
</form>
</body>
</html>

GenericErrorPage.aspx

The following example shows the GenericErrorPage.aspx page. This page creates a safe message
that it displays to remote users. For local users (typically developers and testers of the
application), the page displays a complete exception report. The Page_Error handler redirects
InvalidOperationException errors to this page.

Visual Basic
<%@ Page Language="VB" %>

<script runat="server">
Dim ex As Exception = Nothing

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)


' Get the last error from the server
Dim ex As Exception = Server.GetLastError
' Create a safe message
Dim safeMsg = "A problem has occurred in the web site. "

' Show Inner Exception fields for local access


If ex.InnerException IsNot Nothing Then
innerTrace.Text = ex.InnerException.StackTrace
InnerErrorPanel.Visible = Request.IsLocal
innerMessage.Text = ex.InnerException.Message
End If

' Show Trace for local access


If Request.IsLocal Then
exTrace.Visible = True
Else
ex = New Exception(safeMsg, ex)
End If

' Fill the page fields


exMessage.Text = ex.Message
exTrace.Text = ex.StackTrace

' Log the exception and notify system operators


ExceptionUtility.LogException(ex, "Generic Error Page")
ExceptionUtility.NotifySystemOps(ex)

' Clear the error from the server


Server.ClearError()
End Sub

</script>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head id="Head1" runat="server">
<title>Generic Error Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>
Generic Error Page</h2>
<asp:Panel ID="InnerErrorPanel" runat="server" Visible="false">
<p>
Inner Error Message:<br />
<asp:Label ID="innerMessage" runat="server" Font-Bold="true"
Font-Size="Large" /><br />
</p>
<pre>
<asp:Label ID="innerTrace" runat="server" />
</pre>
</asp:Panel>
<p>
Error Message:<br />
<asp:Label ID="exMessage" runat="server" Font-Bold="true"
Font-Size="Large" />
</p>
<pre>
<asp:Label ID="exTrace" runat="server" Visible="false" />
</pre>
<br />
Return to the <a href='Default.aspx'>Default Page</a>
</div>
</form>
</body>
</html>
C#
<%@ Page Language="C#" %>

<script runat="server">
protected Exception ex = null;

protected void Page_Load(object sender, EventArgs e)


{
// Get the last error from the server
Exception ex = Server.GetLastError();

// Create a safe message


string safeMsg = "A problem has occurred in the web site. ";

// Show Inner Exception fields for local access


if (ex.InnerException != null)
{
innerTrace.Text = ex.InnerException.StackTrace;
InnerErrorPanel.Visible = Request.IsLocal;
innerMessage.Text = ex.InnerException.Message;
}
// Show Trace for local access
if (Request.IsLocal)
exTrace.Visible = true;
else
ex = new Exception(safeMsg, ex);

// Fill the page fields


exMessage.Text = ex.Message;
exTrace.Text = ex.StackTrace;

// Log the exception and notify system operators


ExceptionUtility.LogException(ex, "Generic Error Page");
ExceptionUtility.NotifySystemOps(ex);

// Clear the error from the server


Server.ClearError();
}
</script>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head id="Head1" runat="server">
<title>Generic Error Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>
Generic Error Page</h2>
<asp:Panel ID="InnerErrorPanel" runat="server" Visible="false">
<p>
Inner Error Message:<br />
<asp:Label ID="innerMessage" runat="server" Font-Bold="true"
Font-Size="Large" /><br />
</p>
<pre>
<asp:Label ID="innerTrace" runat="server" />
</pre>
</asp:Panel>
<p>
Error Message:<br />
<asp:Label ID="exMessage" runat="server" Font-Bold="true"
Font-Size="Large" />
</p>
<pre>
<asp:Label ID="exTrace" runat="server" Visible="false" />
</pre>
<br />
Return to the <a href='Default.aspx'> Default Page</a>
</div>
</form>
</body>
</html>

HttpErrorPage.aspx

The following example shows the HttpErrorPage.aspx page. This page also creates a safe
message that depends on the value of the error code, which it displays to remote users. For local
users, the page displays a complete exception report. The Application_Error handler redirects
HttpException errors to this page.

Visual Basic
<%@ Page Language="VB" %>

<script runat="server">
Dim ex As HttpException = Nothing

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)


ex = CType(Server.GetLastError, HttpException)
Dim httpCode As Integer = ex.GetHttpCode

' Filter for Error Codes and set text


If ((httpCode >= 400) AndAlso (httpCode < 500)) Then
ex = New HttpException(httpCode, _
"Safe message for 4xx HTTP codes.", ex)
ElseIf (httpCode > 499) Then
ex = New HttpException(ex.ErrorCode, _
"Safe message for 5xx HTTP codes.", ex)
Else
ex = New HttpException(httpCode, _
"Safe message for unexpected HTTP codes.", ex)
End If

' Log the exception and notify system operators


ExceptionUtility.LogException(ex, "HttpErrorPage")
ExceptionUtility.NotifySystemOps(ex)

' Fill the page fields


exMessage.Text = ex.Message
exTrace.Text = ex.StackTrace

' Show Inner Exception fields for local access


If ex.InnerException IsNot Nothing Then
innerTrace.Text = ex.InnerException.StackTrace
InnerErrorPanel.Visible = Request.IsLocal
innerMessage.Text = _
"HTTP " & httpCode & ": " & ex.InnerException.Message
End If

' Show Trace for local access


exTrace.Visible = Request.IsLocal
' Clear the error from the server
Server.ClearError()
End Sub

</script>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head id="Head1" runat="server">
<title>Http Error Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>
Http Error Page</h2>
<asp:Panel ID="InnerErrorPanel" runat="server" Visible="false">
<asp:Label ID="innerMessage" runat="server" Font-Bold="true"
Font-Size="Large" /><br />
<pre>
<asp:Label ID="innerTrace" runat="server" />
</pre>
</asp:Panel>
Error Message:<br />
<asp:Label ID="exMessage" runat="server" Font-Bold="true"
Font-Size="Large" />
<pre>
<asp:Label ID="exTrace" runat="server" Visible="false" />
</pre>
<br />
Return to the <a href='Default.aspx'>Default Page</a>
</div>
</form>
</body>
</html>
C#
<%@ Page Language="C#" %>

<script runat="server">
protected HttpException ex = null;

protected void Page_Load(object sender, EventArgs e)


{
ex = (HttpException)Server.GetLastError();
int httpCode = ex.GetHttpCode();

// Filter for Error Codes and set text


if (httpCode >= 400 && httpCode < 500)
ex = new HttpException
(httpCode, "Safe message for 4xx HTTP codes.", ex);
else if (httpCode > 499)
ex = new HttpException
(ex.ErrorCode, "Safe message for 5xx HTTP codes.", ex);
else
ex = new HttpException
(httpCode, "Safe message for unexpected HTTP codes.", ex);

// Log the exception and notify system operators


ExceptionUtility.LogException(ex, "HttpErrorPage");
ExceptionUtility.NotifySystemOps(ex);

// Fill the page fields


exMessage.Text = ex.Message;
exTrace.Text = ex.StackTrace;

// Show Inner Exception fields for local access


if (ex.InnerException != null)
{
innerTrace.Text = ex.InnerException.StackTrace;
InnerErrorPanel.Visible = Request.IsLocal;
innerMessage.Text = string.Format("HTTP {0}: {1}",
httpCode, ex.InnerException.Message);
}
// Show Trace for local access
exTrace.Visible = Request.IsLocal;

// Clear the error from the server


Server.ClearError();
}
</script>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head id="Head1" runat="server">
<title>Http Error Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>
Http Error Page</h2>
<asp:Panel ID="InnerErrorPanel" runat="server" Visible="false">
<asp:Label ID="innerMessage" runat="server" Font-Bold="true"
Font-Size="Large" /><br />
<pre>
<asp:Label ID="innerTrace" runat="server" />
</pre>
</asp:Panel>
Error Message:<br />
<asp:Label ID="exMessage" runat="server" Font-Bold="true"
Font-Size="Large" />
<pre>
<asp:Label ID="exTrace" runat="server" Visible="false" />
</pre>
<br />
Return to the <a href='Default.aspx'>Default Page</a>
</div>
</form>
</body>
</html>

Http404ErrorPage.aspx

The following example shows the Http404ErrorPage.aspx page. ASP.NET redirects unhandled
HTTP 404 (file not found) errors to this page. The page displays the same message to remote and
local users.

Visual Basic
<%@ Page Language="VB" %>

<script runat="server">
Dim ex As HttpException

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)


' Log the exception and notify system operators
ex = New HttpException("defaultRedirect")
ExceptionUtility.LogException(ex, "Caught in DefaultRedirectErrorPage")
ExceptionUtility.NotifySystemOps(ex)
End Sub

</script>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head id="Head1" runat="server">
<title>HTTP 404 Error Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>
HTTP 404 Error Page</h2>
Standard error message suitable for file not found errors.
The original exception object is not available,
but the original requested URL is in the query string.<br />
<br />
Return to the <a href='Default.aspx'> Default Page</a>
</div>
</form>
</body>
</html>
C#
<%@ Page Language="C#" %>

<script runat="server">
protected HttpException ex = null;

protected void Page_Load(object sender, EventArgs e)


{
// Log the exception and notify system operators
ex = new HttpException("HTTP 404");
ExceptionUtility.LogException(ex, "Caught in Http404ErrorPage");
ExceptionUtility.NotifySystemOps(ex);
}
</script>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head id="Head1" runat="server">
<title>HTTP 404 Error Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>
HTTP 404 Error Page</h2>
Standard error message suitable for file not found errors.
The original exception object is not available,
but the original requested URL is in the query string.<br />
<br />
Return to the <a href='Default.aspx'> Default Page</a>
</div>
</form>
</body>
</html>

DefaultRedirectErrorPage.aspx

The following example shows the DefaultRedirectErrorPage.aspx page. ASP.NET redirects any
unhandled errors except HTTP 404 errors to this page. The page displays the same message to
remote and local users.

Visual Basic
<%@ Page Language="VB" %>
<script runat="server">
Dim ex As HttpException

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)


' Log the exception and notify system operators
ex = New HttpException("defaultRedirect")
ExceptionUtility.LogException(ex, "Caught in DefaultRedirectErrorPage")
ExceptionUtility.NotifySystemOps(ex)
End Sub

</script>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head id="Head1" runat="server">
<title>DefaultRedirect Error Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>
DefaultRedirect Error Page</h2>
Standard error message suitable for all unhandled errors.
The original exception object is not available.<br />
<br />
Return to the <a href='Default.aspx'>Default Page</a>
</div>
</form>
</body>
</html>
C#
<%@ Page Language="C#" %>

<script runat="server">
protected HttpException ex = null;

protected void Page_Load(object sender, EventArgs e)


{
// Log the exception and notify system operators
ex = new HttpException("defaultRedirect");
ExceptionUtility.LogException(ex, "Caught in DefaultRedirectErrorPage");
ExceptionUtility.NotifySystemOps(ex);
}
</script>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head id="Head1" runat="server">
<title>DefaultRedirect Error Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>
DefaultRedirect Error Page</h2>
Standard error message suitable for all unhandled errors.
The original exception object is not available.<br />
<br />
Return to the <a href='Default.aspx'> Default Page</a>
</div>
</form>
</body>
</html>

ASP.NET
How to: Handle Application-Level Errors

Updated: April 2009

This code example shows how to create an error handler in the Global.asax file that will catch all
unhandled ASP.NET errors while processing a request — in other words, all the errors that are
not caught with a Try/Catch block or in a page-level error handler. In the example, the handler
transfers control to a generic error page named GenericErrorPage.aspx, which interprets the error
and displays an appropriate message.

Example

The following example is from a complete code sample in Complete Example for Error
Handlers.

Security Note:
Never set customErrors to Off in your Web.config file if you do not have an Application_Error
handler in your Global.asax file. Potentially compromising information about your Web site can
be exposed to anyone who can cause an error to occur on your site.
Visual Basic
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
' Code that runs when an unhandled error occurs

' Get the exception object.


Dim exc As Exception = Server.GetLastError

' Handle HTTP errors (avoid trapping HttpUnhandledException


' which is generated when a non-HTTP exception
' such as the ones generated by buttons 1-3 in
' Default.aspx is not handled at the page level).
If (exc.GetType Is GetType(HttpException)) Then
' The Complete Error Handling Example generates
' some errors using URLs with "NoCatch" in them;
' ignore these here to simulate what would happen
' if a global.asax handler were not implemented.
If exc.Message.Contains("NoCatch") Then
Return
End If

'Redirect HTTP errors to HttpError page


Server.Transfer("HttpErrorPage.aspx")
End If

' For other kinds of errors give the user some information
' but stay on the default page
Response.Write("<h2>Global Page Error</h2>" & vbLf)
Response.Write("<p>" & exc.Message + "</p>" & vbLf)
Response.Write(("Return to the <a href='Default.aspx'>" _
& "Default Page</a>" & vbLf))

' Log the exception and notify system operators


ExceptionUtility.LogException(exc, "DefaultPage")
ExceptionUtility.NotifySystemOps(exc)

' Clear the error from the server


Server.ClearError()
End Sub
C#
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs

// Get the exception object.


Exception exc = Server.GetLastError();

// Handle HTTP errors


if (exc.GetType() == typeof(HttpException))
{
// The Complete Error Handling Example generates
// some errors using URLs with "NoCatch" in them;
// ignore these here to simulate what would happen
// if a global.asax handler were not implemented.
if (exc.Message.Contains("NoCatch"))
return;

//Redirect HTTP errors to HttpError page


Server.Transfer("HttpErrorPage.aspx");
}

// For other kinds of errors give the user some information


// but stay on the default page
Response.Write("<h2>Global Page Error</h2>\n");
Response.Write(
"<p>" + exc.Message + "</p>\n");
Response.Write("Return to the <a href='Default.aspx'>" +
"Default Page</a>\n");

// Log the exception and notify system operators


ExceptionUtility.LogException(exc, "DefaultPage");
ExceptionUtility.NotifySystemOps(exc);

// Clear the error from the server


Server.ClearError();
}
Robust Programming

An error handler that is defined in the Global.asax file will only catch errors that occur during
processing of requests by the ASP.NET runtime. For example, it will catch the error if a user
requests an .aspx file that does not occur in your application. However, it does not catch the error
if a user requests a nonexistent .htm file. For non-ASP.NET errors, you can create a custom
handler in Internet Information Services (IIS). The custom handler will also not be called for
server-level errors.

You cannot directly output error information for requests from the Global.asax file; you must
transfer control to another page, typically a Web Forms page. When transferring control to
another page, use Transfer method. This preserves the current context so that you can get error
information from the GetLastError method.

After handling an error, you must clear it by calling the ClearError method of the Server object
(HttpServerUtility class).

Security

Be sure that you do not display error information that might help malicious users compromise
your application. For details, see How to: Display Safe Error Messages.

ASP.NET
How to: Handle Page-Level Errors

If possible, you should handle errors in Try/Catch blocks within your code, because a problem is
more easily corrected where it occurs. If the user can help correct a problem, the page needs to
return to the same place so the user has a context for understanding what to do.

A page-level handler returns you to the page, but there is no longer anything on the page because
instances of controls are not created. To provide the user any information, you must specifically
write it to the page.

You would probably use a page-level error handler to log unhandled errors or to take the user to
a page that can display helpful information.

This code example shows a handler for the Error event in an ASP.NET Web page. This handler
catches all exceptions that are not already handled within Try/Catch blocks in the page.

After you handle an error, you must clear it by calling the ClearError method of the Server object
(HttpServerUtility class).

Example
This handler filters for specific kinds of exceptions. For an ArgumentOutOfRangeException
exception, the handler writes some text on the page, provides a link back to the page, logs the
error, and notifies system administrators. For an InvalidOperationException exception, the
handler simply transfers the exception to the Generic Error Page. For any other kind of
exception, the handler does nothing, which allows your site to automatically redirect to the
generic page specified in the Web.config file. Your own code would filter for exceptions that are
important to your application.

The following example is part of a complete code sample in Complete Example for Error
Handlers

Visual Basic
Private Sub Page_Error(ByVal sender As Object, ByVal e As EventArgs)
' Get last error from the server
Dim exc As Exception = Server.GetLastError

' Handle exceptions generated by Button 1


If TypeOf exc Is InvalidOperationException Then
' Pass the error on to the Generic Error page
Server.Transfer("GenericErrorPage.aspx", True)

' Handle exceptions generated by Button 2


ElseIf TypeOf exc Is ArgumentOutOfRangeException Then
' Give the user some information, but
' stay on the default page
Response.Write("<h2>Default Page Error</h2>" & vbLf)
Response.Write(("<p>Provide as much information here as is " _
& "appropriate to show to the client.</p>" & vbLf))
Response.Write(("Return to the <a href='Default.aspx'>" _
& "Default Page</a>" & vbLf))
' Log the exception and notify system operators
ExceptionUtility.LogException(exc, "DefaultPage")
ExceptionUtility.NotifySystemOps(exc)
' Clear the error from the server
Server.ClearError()
Else
' Pass the error on to the default global handler
End If
End Sub
C#
private void Page_Error(object sender, EventArgs e)
{
// Get last error from the server
Exception exc = Server.GetLastError();

// Handle exceptions generated by Button 1


if (exc is InvalidOperationException)
{
// Pass the error on to the Generic Error page
Server.Transfer("GenericErrorPage.aspx", true);
}

// Handle exceptions generated by Button 2


else if (exc is ArgumentOutOfRangeException)
{
// Give the user some information, but
// stay on the default page
Response.Write("<h2>Default Page Error</h2>\n");
Response.Write("<p>Provide as much information here as is " +
"appropriate to show to the client.</p>\n");
Response.Write("Return to the <a href='Default.aspx'>" +
"Default Page</a>\n");

// Log the exception and notify system operators


ExceptionUtility.LogException(exc, "DefaultPage");
ExceptionUtility.NotifySystemOps(exc);

// Clear the error from the server


Server.ClearError();
}
else
{
// Pass the error on to the default global handler
}
}

ASP.NET
ASP.NET Debugging

Application code can contain various types of errors, or bugs. Most syntax errors are caught
during compilation. However, other types of errors require that you debug your code — that is,
that you examine the code while it is running to validate that the execution path and data is as it
should be.

The topics in this section provide information about how to use the debugger in the Windows
Software Development Kit (SDK) to help you find errors in ASP.NET Web pages.

In This Section
ASP.NET Debugging Overview
Using the Debugger with Web Pages
What's New in the Visual Studio Debugger
How to: Set Up Remote Debugging
Debugging ASP.NET and AJAX Applications

ASP.NET
ASP.NET Debugging Overview

Application code can contain various types of errors, or bugs. Most syntax errors are caught
during compilation. However, other types of errors require that you debug your code — that is,
that you examine the code while it is running to validate that the execution path and data is as it
should be.
This topic provides information about how to use the debugger in the Windows Software
Development Kit (SDK) to help you find errors in ASP.NET Web pages.

Background

Application code can contain various types of errors, or bugs. Most syntax errors are caught
during compilation. However, other types of errors require that you debug your code — that is,
that you examine the code while it is running to validate that the execution path and data is as it
should be. For more information, see Debugging and Profiling Applications.

The Windows Software Development Kit (SDK) includes a tool called Visual Debugger that
allows you to examine an application while it is running. This tool is located in %ProgramFiles
%\Microsoft Visual Studio 8\SDK\v2.0\GuiDebug\DbgCLR.exe. Using the debugger, you can
see exactly how your application is working by stepping through each statement as it executes
and by viewing the data in each variable. To use Visual Debugger, open it and then attach it to
the process that is running the pages of your ASP.NET application. In Internet Information
Services (IIS) versions 5.0 and 5.1, and in IIS 6.0 running in IIS 5.0 application mode, the
process to which you attach the debugger is the ASP.NET worker process (Aspnet_wp.exe). In
IIS 6.0 running in worker process isolation mode, the process that you attach to is the thread pool
process (W3wp.exe). When the debugger is attached to a process, you can view everything going
on during that process, and the debugger maps the instructions being executed in the process
back to your original code so that you can see each line of code being executed.

Visual Debugger

Visual Debugger allows you to examine code while it is running and includes features that help
you debug applications, including the following:

• Breakpoints Breakpoints are places in the code where the debugger will stop the
application, allow you to view the current data state of the application, and then step
through each line of code. For information, see Debugging Basics: Breakpoints.
• Stepping Once you have stopped at a breakpoint, you can run the code line by line
(known as stepping through the code). Visual Debugger includes a number of features to
help you step through your code, such as iterators that allow you to specify how many
times to step through a loop before stopping again. For more information, see Code
Stepping Overview.
• Data Viewing Visual Debugger gives you many different options for viewing and
tracking data while the application is running. The debugger allows you to modify the
data while the application is stopped in break mode and then continue to run the
application with the modified data. For more information, see Viewing Data in the
Debugger.

Note:
The Edit and Continue feature of Visual Studio 2005 is not available for Web applications.

For more information, see Using the Debugger with Web Pages.
Configuring ASP.NET Web Applications for Debugging

To enable debugging for an ASP.NET Web application, you must configure the application to
compile into a debug build. A debug build includes information that the debugger needs so that it
can step through your code and display the contents of variables. You configure your Web
application for debug builds in the Compilation section of your application's Web.config file. For
more information, see compilation Element (ASP.NET Settings Schema). Alternatively, if you
want to debug only single pages, you can add debug=true to the @ Page directive on the pages
that you wish to debug. For more information, see How to: Enable Debugging for ASP.NET
Applications.

Note:
An application compiled into a debug build will perform considerably more slowly than if it is
compiled into a retail build. Be sure you have debug mode turned off before you deploy your
application. Additionally, in debug mode, more information is exposed in the stack when an error
occurs and can be a potential security issue.

Local and Remote Debugging

If you are running a Web server locally, such as IIS, you can debug applications running locally
on your computer so that you can view your pages in a browser.

If you cannot run a page locally, because you cannot run a Web server or because the application
is not available to you locally, you can debug an application running on another server. In order
to debug remotely, you must install the Visual Studio remote debugging components on the
remote server. For more information, see How to: Set Up Remote Debugging.

Permissions for Debugging

Debugging a process requires more privileges than running it. Therefore, in addition to
configuring your application for debugging, you must also ensure that you have adequate
permissions to attach to a process in order to debug it. Users have the permission to debug
processes running under their own user local identity, but they cannot debug other user's
processes. Administrators can debug any process.

To debug on a remote server, you need administrator privileges on the computer where the
process to be debugged runs. For more information, see How to: Debug Web Applications on a
Remote Server.

Client-Side Script Debugging

In addition to server-side application debugging, Visual Debugger allows you to debug client
script written in ECMAScript (JavaScript) or VBScript. Client-script debugging can be
especially useful when you have Web server controls that use client-side script.

Visual Web Developer


Debugging Web Pages Overview

The ASP.NET page framework provides extensive support for debugging Web applications.
However, because Web applications are distributed, there are some special issues associated with
debugging them.

In general, you debug Web applications the same way you do other types of Visual Studio
applications. You can set breakpoints, start the debugger, break into code, examine variables, and
perform all the functions associated with the Visual Studio debugger. For details, see Debugger
Roadmap. In addition, the ASP.NET page framework provides a trace mode that enables you to
insert instrumentation messages into your forms. For details, see Walkthrough: Using Tracing in
Visual Web Developer to Help Find Web Page Errors and Walkthrough: Integrating ASP.NET
Tracing with System.Diagnostics Tracing.

Debugger Configuration

Web application debugging requires certain components on the computer where debugging is to
happen and requires that you have adequate permissions.

Local Computer Configuration

If you are running Web applications locally on your computer—that is, the Web server is on
your computer—then the computer has the correct components automatically.

You must still make sure that you have adequate permissions to debug. Users have the
permission to debug processes running under their user identity, but cannot debug other user's
processes. Administrators can debug any process.

Remote Computer Configuration

If the Web server is on another computer (a remote server), you must ensure that the computer is
configured properly. This involves:

• Making sure that DCOM is installed on both your computer and on the server. Windows
2000 and Windows Server 2003 normally have DCOM installed already, so there is
usually no action required on your part.
• Installing Visual Studio server-side components on the remote computer. You can do this
by running the Visual Studio installation process on the remote computer and selecting
the option for server components.
• Ensuring that any debugger users have permissions to attach to a Web server process.
This means that server processes must either run as the user (impersonation) or that users
who want to debug must have administrative privileges on the Web server. (Giving users
administrative privileges on the server might not be in keeping with your security
policies.) You can control ASP.NET impersonation using the identity element of the
Web.config file for your application. For details, see <identity> Element.
For details about configuring for remote debugging, see Debugging Web Applications on a
Remote Server.

Whether you are running locally or on a remote computer, you must be sure that debugging is
enabled for your Web application specifically. This is done in the compilation Element
(ASP.NET Settings Schema) element of the Web.config file that is part of your Web application
project. This setting instructs the compiler to insert debugging symbols into the application's
compiled code so that you can use the debugger with it. You can enable debugging using the
Web Site Administration Tool. For details, see Walkthrough: Debugging Web Pages in Visual
Web Developer.

Debugging Client Script

Client script runs within the browser, separately from the code in your Web application, which
runs on the server. You can use the Visual Studio debugger to debug client script. The debugger
does not enable you to follow execution from server code to client script; however, it does
support most other debugging functionality for client script.

You can debug client script in various ways. From within Visual Studio, you can use debugger
commands to attach to the browser process (Iexplore.exe) and break into the script. From there,
you can use the debugger as you would for any other code.

Error Handling in ASP.NET


Introduction

When errors occur in an ASP.NET application, they either get handled or propagates unhandled
to higher scopes. When an unhandled exception propagates, the user may be redirected to an
error page using different ASP.NET configuration settings. However, such a redirection may be
prevented in the first place by handling the exceptions that get thrown. Error handling in
ASP.NET therefore, may be divided into two separate logics:

• Redirecting the user to an error page when errors go unhandled.


• Handling exceptions when they get thrown.

Redirecting the user to an error page

There are two different scopes where we could specify which page the user should be redirected
to, when errors go unhandled:

• Page level (applies to errors that happen within a single page).


• Application level (applies to errors that happen anywhere in the application).

Page Level

Use the errorPage attribute in the webform.

This attribute defines the page the user should be redirected to when an unhandled exception
occurs in that specific page. For example,

Collapse

<%@ Page language="c#" Codebehind="WebForm1.aspx.cs"


AutoEventWireup="false" Inherits="WebTest.WebForm1"
errorPage="/WebTest/ErrorPages/PageError.html"%>

The errorPage attribute maps to the Page.ErrorPage property, and hence may be set
programmatically. The value may optionally include query string parameters. If no parameters
are added, ASP.NET would automatically add one with the name aspxerrorpath. This
parameter would hold the value of the relative URL to this page, so that the error page would be
able to determine which page caused the error.

If a value is specified in this attribute (or property) and an unhandled exception occurs in the
page, the Page class would automatically perform a redirect to the specified page. If a value is
not specified, the exception is assumed to be unhandled, wrapped in a new
HttpUnhandledException and then thrown, propagating it to the next higher level.

Application Level

Use the customErrors section in web.config.


This section lets you specify the error page to which the user should be redirected to when an
unhandled exception propagates in the application level. This section specifies error pages for
both default errors as well as the HTTP status code errors.

Collapse

<customErrors mode="On" defaultRedirect="/WebTest/ErrorPages/AppError.html">


<error statusCode="404" redirect="/WebTest/ErrorPages/404.html" />
</customErrors>

The mode attribute specifies whether to show user-defined custom error pages or ASP.NET error
pages. Three values are supported for this attribute:

• RemoteOnly - Custom error pages are shown for all remote users. ASP.NET
error pages with rich error information are displayed only for local users.
• On - Custom error pages are always shown, unless one is not specified. When
a custom error page is not defined, an ASP.NET error page will be displayed
which describes how to enable remote viewing of errors.
• Off - Custom error pages are not shown. Instead, ASP.NET error pages will be
displayed always, which will have rich error information.

It's a bad idea to give users more information than what is required. ASP.NET error pages
describe technical details that shouldn't be exposed. Ideally, the mode attribute thus should not be
set to Off.

The defaultRedirect attribute specifies the path to a generic error page. This page would
typically have a link to let the user go back to the home page or perform the request once again.

Each error element defines a redirect specific to a particular HTTP status code. For example, if
the error is a 404 (File Not Found), then you could set the error page as FileNotFound.htm. You
could add as many error elements in the customErrors section as required, each of which
specifies a status code and the corresponding error page path. If ASP.NET can�t find any
specific error element corresponding to a status code, it would use the value specified in the
defaultRedirect attribute.

Notes

• The settings specified in the page level (errorPage attribute) would override
those specified in the customErrors section. The reason is because errors in
the page would be handled by the Page class first, which might thus prevent
the exception from being propagated to the application level. It�s only when
the Page class fails to handle the exception that the values set in
customErrors come into scope.
• All these settings mentioned above apply only for requests that are made for
ASP.NET files. More specifically, these settings would work only for requests
for files with extensions that are mapped to the aspnet_isapi. For example, if
you request for an ASP or JPG file (extensions that are not mapped to
aspnet_isapi) which does not exist, then these settings won�t work, and the
standard error page specified in IIS would be displayed. To modify this
behavior, either map the required extensions to aspnet_isapi or modify the
custom error pages specified in IIS.

Handling exceptions

There are different levels where you could handle exceptions.

• Locally (method level), where exceptions could be thrown.


• Page level by handling the Page.Error event.
• Application level by handling the HttpApplication.Error event.
• HTTP Module level by handling the HttpApplication.Error event.

Local error handling

Wrap code that might throw exceptions in a try-catch-finally block.

If you can recover from the exception, then handle it in the catch block. If the exception cannot
be recovered from locally, let the exception propagate to higher levels by throwing it. If the
exception cannot be recovered from locally, but additional information can be provided, then
wrap the exception with the new information and throw the new exception. This method is used
when you use custom exceptions. Place the clean up code in the finally block.

Find more information on exception handling best practices available in MSDN.

Note: The more exceptions you catch and throw, the slower your application would run. This is
more significant in web applications.

Page Level

Attach a handler to the Page.Error event. In C#, you will have to write the event wire up code
yourself in the Page_Load method.

When an exception goes unhandled in a page, the Error event of the Page class gets triggered.

Typically, the first action you would perform in this handler would be to obtain the exception
thrown, by using the Server.GetLastError method. This method would return a reference to
the last Exception object that was thrown.

After you get the Exception object, you will want to redirect the user to an error page. We could
make ASP.NET do the redirection by using the errorPage attribute of the Page (design time) or
by using the Page.ErrorPage property (runtime). Obviously, the choice here would be to
programmatically set the value using the Page.ErrorPage property in the event handler.

Collapse
private void WebForm1_Error(object sender, EventArgs e)
{
// Get the last exception thrown

Exception ex = Server.GetLastError();

// Do something with the exception like logging etc.

// Set the error page

this.ErrorPage = "/ErrorHandling/ErrorPages/BaseError.html";
}

If you do not specify an error page, the exception gets wrapped inside an
HttpUnhandledException object and propagates. If you don�t want the exception to be
wrapped, then simply throw the last exception, which would force immediate propagation
escaping any intervention. However, this would prevent ASP.NET from redirecting the user to a
page specific page either. In other words, if you are going to throw the last error (or any
exception for that matter), setting the error page will have no effect.

Collapse

private void BasePage_Error(object sender, EventArgs e)


{
// Get the last exception thrown

Exception ex = Server.GetLastError();

// Do something with the exception like logging etc.

// The statement below has no significance - it's as good as commented

this.ErrorPage = "/ErrorHandling/ErrorPages/BaseError.html";

// Throw the error to prevent wrapping

throw ex;
}

To reduce redundant code, you could define a base web form page which defines the
Page.Error event handler and then wire up code in the constructor, and then make all your Web
Form pages derive from this base page. This would save you the effort of writing the error
handler in each web form.

Application Level

Attach an event handler to the Application.Error event.

When an unhandled exception leaves a page, it gets propagated to the application level, which
would trigger this event.
There are two things you would want to do in an application error handler.

• Get the last exception thrown using Server.GetLastError.


• Clear the error using Server.ClearError, to inform ASP.NET that you have
handled the error.

If you don�t clear the error, the exception would propagate. However, since there isn't any
higher scope where the exception could be caught, ASP.NET is forced to handle it. The way
ASP.NET handles the exception depends upon the settings specified in the customErrors
section we saw before. If no settings are defined, ASP.NET would use the defaults and display
the infamous 'yellow' error page.

HTTP Module Level

Instead of handling application errors in global.asax, exceptions may also be handled by


attaching an HTTP Module which would have a handler attached to the Application.Error
event. This method would be triggered before the corresponding application handler would be
invoked. Such an implementation would be beneficial if you have multiple projects with the
same global error handling implementation. In such a scenario, you could create a module and
attach it to each web application you have.

All the points we saw in the Page and Application handlers apply to the Module handler as well.

Important Notes

Prevent infinite recursion

If an error occurs in the error handling code, an infinite recursive loop would result, which would
soon drag your server down. The reason why this happens is because the new exception would
trigger the error event once again which would in turn redirect control to the handler, which
would cause yet another exception to be thrown, making an infinite loop.

This might also happen if the error page itself throws an exception. To counter this possibility,
making error pages static is a good idea.

Errors may also happen while attempting to redirect to an error page using Server.Transfer or
Response.Redirect maybe due to an invalid path. To tackle this scenario, we could wrap the
redirection code in a try-catch block. If the redirection fails, then we have nothing more to do
other than setting the response code and completing the response, using the
Response.StatusCode property and the HttpApplication.CompleteResponse method. This
would then be handled by the settings specified in the customErrors section.

Parser Errors
Parser errors are caused due to invalid tags (or similar reasons) in an aspx page. These errors are
usually of type HttpParseException. Such errors will not be caught by the Page level handler
as page parsing happens before ASP.NET creates the assembly for the aspx page. In other words,
parser errors are thrown while ASP.NET reads the aspx file and tries to create its assembly, and
hence is way before the corresponding type is created. Thus, such errors will have to be handled
in the application scope.

Exception logging and response time

Users need to get responses as quick as possible. Implementation wise, this means that when
errors happen, error recovery processes should be quick and users should be redirected or
informed of the error as soon as possible. If exceptions are going to be logged to a file or other
mediums, then it could take time which would lead to a slow response. Making exception
logging an asynchronous process would be a good idea in this respect.

ASP.NET
Using the Debugger with Web Pages

The topics in this section provide details about how to use debugger features to examine running
code in an ASP.NET application.

In This Section
Attaching to Running Processes
Debugging Basics: Breakpoints
Execution Control
Viewing Data in the Debugger

Visual Studio Debugger


Attaching to Running Processes

This topic applies to:

Edition Visual Basic C# C++ Web Developer


Express
Standard
Pro and Team

Table legend:

Applies
Does not apply
Command or commands hidden by default.
The Visual Studio debugger has the ability to attach to a process that is running outside of Visual
Studio. You can use this attach capability to do the following:

• Debug an application that was not created in Visual Studio.


• Debug multiple processes simultaneously. You can also debug multiple processes by
starting multiple projects within a single solution.
• Debug a process running on a remote computer.
• Debug a DLL that runs in a separate process that cannot easily be started from Visual
Studio, for example, a service or an ISAPI DLL running with Internet Information
Services.
• Start the debugger automatically when a process crashes while running outside of Visual
Studio. This is Just-In-Time debugging.

After you have attached to a program, you can use debugger execution commands, inspect the
program state, and so on. For more information, see Execution Control and Viewing Data in the
Debugger. Your ability to inspect the program may be limited, of course, depending on whether
the program was built with debug information and whether you have access to the program's
source code, and whether the common language runtime JIT compiler is tracking debug
information.

Note:
For the debugger to attach to code written in C++, the code needs to emit DebuggableAttribute.
You can add this to your code automatically by linking with the /ASSEMBLYDEBUG linker
option.

Visual Studio Debugger


Debugging Basics: Breakpoints

This topic applies to:

Edition Visual Basic C# C++ Web Developer


Express
Standard
Pro and Team

Table legend:

Applies
Does not apply
Command or commands hidden by default.

A breakpoint is a signal that tells the debugger to temporarily suspend execution of your program
at a certain point. When execution is suspended at a breakpoint, your program is said to be in
break mode. Entering break mode does not terminate or end the execution of your program.
Execution can be resumed at any time.
You can think of break mode as being like a timeout. All the elements remain, functions,
variables, and objects remain in memory, for example, but their movements and activities are
suspended. During break mode, you can examine their positions and states to look for violations
or bugs. You can make adjustments to the program while in break mode. You can change the
value of a variable, for example. You can move the execution point, which changes the statement
that will be executed next when execution resumes. In C++, C#, and Visual Basic, you can even
make changes to the code itself while in break mode using a powerful feature called Edit and
Continue.

Breakpoints provide a powerful tool that enables you to suspend execution where and when you
need to. Rather than stepping through your code line-by-line or instruction-by-instruction, you
can allow your program to run until it hits a breakpoint, then start to debug. This speeds up the
debugging process enormously. Without this ability, it would be virtually impossible to debug a
large program.

Many programming languages have statements or constructs that suspend execution and put your
program into break mode. Visual Basic, for example, has the Stop statement. Breakpoints differ
from these statements because breakpoints are not actual source code that has to be added to your
program. You do not type a breakpoint statement into a source window. You request a
breakpoint through the debugger interface, and the debugger sets it for you. To insert a line
breakpoint, click in the gray margin next to the line where you want to set the breakpoint. More
complex breakpoints can be handled through a full-featured Breakpoints window.

Breakpoints have many advantages over debugging constructs such as the Visual Basic Stop
statement. Breakpoints can be deleted or changed without having to change your program's
source code. Because breakpoints are not statements, they never produce any extra code when
you build a release version of your program. If you use Stop statements in your program, you
need to manually remove the Stop statements before building the release version, or use
conditionals, as shown here:

#If DEBUG Then


Stop
#End If

If you want to disable a Stop statement temporarily, you need to locate the statement in your
source code and comment it out:

' Stop

This is no problem if you only have one Stop statement. If you are debugging a large program
with lots of Stop statements, however, searching for all of the statements and commenting each
one out can be time consuming. With breakpoints, you can select and disable or enable any or all
of your breakpoints from the Breakpoints window.

Finally, breakpoints have a big advantage over Stop statements in their flexibility. A Stop
statement causes execution to break on the source line where the statement is located. You can
set a breakpoint on a source line that does the same thing. Alternatively, you can also set a
breakpoint on a function or a memory address, which cannot be done with Stop statements. In
addition to these location breakpoints, the Visual Studio debugger offers data breakpoints for
native only. A data breakpoint is set on a global or local variable, rather than a location in the
code. Setting a data breakpoint causes execution to break when the value of that variable
changes.

To provide even greater flexibility, the Visual Studio debugger enables you to set properties that
modify the behavior of a breakpoint:

• Hit Count enables you to determine how many times the breakpoint is hit before the
debugger breaks execution. By default, the debugger breaks execution every time the
breakpoint is hit. You can set a hit count to tell the debugger to break every two times the
breakpoint is hit, or every 10 times, or every 512 times, any number you choose. Hit
counts can be useful because some bugs do not appear the first time your program
executes a loop, calls a function, or accesses a variable. Sometimes, the bug might not
show up until the 100th or 1000th iteration. To debug such a problem, you can set a
breakpoint with a hit count of 100 or 1000.
• Condition is an expression that determines whether the breakpoint is hit or skipped.
When the debugger reaches the breakpoint, it will evaluate the condition. The breakpoint
will be hit only if the condition is satisfied. You can use a condition with a location
breakpoint to stop at a specified location only when a certain condition is true. Suppose
you are debugging a banking program, for example, where the account balance is never
allowed to go below zero. You might set breakpoints at certain locations in the code and
attach condition like balance < 0 to each one. When you run the program, execution will
break at those locations only when the balance is less than zero. You can examine
variables and program state at the first breakpoint location, then continue execution to the
second breakpoint location, and so on.
• Action specifies something that should occur when the breakpoint is hit. By default, the
debugger breaks execution, but you can choose to print a message or run a Visual Studio
macro instead. If you choose to print a message instead of breaking, the breakpoint has an
effect very similar to a Trace statement. This method of using breakpoints is called
tracepoints.
• Filter provides a way to specify a process or thread for the breakpoint.

Note:
One particularly useful technique is setting breakpoints in the Call Stack window. Using
the Call Stack window, you can set a breakpoint on a particular function call. This can be
especially useful when you are debugging a recursive function, a function that calls itself.
If you break execution after a certain number of calls, you can use the Call Stack window
to set a breakpoint on a previous call that has not yet returned. The debugger will
encounter that breakpoint and break execution on the way out of the current calls.

Visual Studio Debugger


Execution Control
This topic applies to:

Edition Visual Basic C# C++ Web Developer


Express
Standard
Pro and Team

Table legend:

Applies
Does not apply
Command or commands hidden by default.

The Visual Studio debugger provides powerful commands for controlling the execution of your
application. The following topics describe the tasks you can perform, using debugger commands,
to control execution:

• Starting (or Continuing) Execution


• Breaking Execution
• Stopping Execution
• Stepping Through Your Application
• Running to a Specified Location
• Setting the Execution Point

Visual Studio Debugger


Viewing Data in the Debugger

This topic applies to:

Edition Visual Basic C# C++ Web Developer


Express
Standard
Pro and Team

Table legend:

Applies
Does not apply
Command or commands hidden by default.

The Visual Studio debugger provides a variety of tools for inspecting and modifying the state of
your program. Most of these tools function only in break mode.

DataTips
DataTips are one of the most convenient tools for viewing information about the variables and
objects in your program during debugging. When the debugger is in break mode, you can view
the value of a variable within the current scope by placing the mouse pointer over the variable in
a source window. In Visual Studio 2005, DataTips have been enhanced to enable more
convenient and powerful viewing of complex data types. For more information, see How to: Use
DataTips.

Visualizers

Visualizers are a new component of the Visual Studio debugger that enable you to view the
contents of an object or variable in a meaningful way. For example, you can use the HTML
visualizer to view an HTML string as it would be interpreted and displayed in a browser. You
can access visualizers from DataTips, the Watch window, the Autos window, the Locals
window, or the QuickWatch dialog box. For more information, see Visualizers.

Variable Windows

You can use Variable Windows to study variables, register contents, and expressions.

You can set the numeric format used in the debugger windows to decimal or hexadecimal. For
more information, see Changing the Numeric Format of Debugger Windows.

Other Debugger Windows

The following debugger windows offer important information about your program.

To view Try
How to: Use the Registers
Register contents
Window
Memory contents How to: Use the Memory Window
• Names of functions on the call stack
• Parameter types How to: Use the Call Stack
Window
• Parameter values
How to: Use the Disassembly
Assembly code generated by the compiler for your program
Window
Threads — sequential streams of execution — created by your
How to: Use the Threads Window
program
Modules (DLLs and EXEs) used by your program How to: Use the Modules Window
Note:
Your ability to inspect the program may be limited by whether the program was built with debug
information, whether the debugger has access to the source code, and whether the common
language runtime Just-In-Time (JIT) compiler is tracking debug information. If the Visual Studio
debugger does not find debug information for your program, it reports "no matching symbolic
information found". Debug information is generated by default when you build the debug
configuration of your program. In the debugger cannot find symbols, you may need to specify a
symbol path. For more information, see How to: Specify a Symbol Path. To aid in debugging
system calls, you can install system debug symbols. For more information, see Installing System
Debug Symbols.

Visual Studio Debugger


What's New in the Visual Studio Debugger

The debugger has been enhanced by the addition of the following features:

• The Step Into Specific command now works with managed as well as native code. For
more information, see How to: Step Into a Specific Function.
• The debugger no longer steps into managed properties and operators by default. For more
information, see How to: Step Into Properties and Operators in Managed Code.
• You can now step into .NET Framework source code when debugging. For more
information, see How to: Debug .NET Framework Source.

Changes in the Visual Studio 2008 Debugger

The Visual Studio 2008 debugger has been enhanced by the addition of the following features:

• Remote debugging support for Windows Vista.

You can remote debug to or from a platform running the Windows Vista operating
system. For more information, see How to: Set Up Remote Debugging.

• Better support for debugging multithreaded applications.

Improvements to the Threads window, flagging threads of special interest, thread markers
in a source window, and switching threads in a source window. For more information,
see Debugging Multithreaded Applications.

• Debugging support for LINQ programming.

You can debug LINQ queries, including LINQ to SQL Queries. For more information,
see Debugging LINQ.

• Debugging support for Windows Communications Foundation.

For more information, see Debugging WCF Services.

• Better support for script debugging, including:


o Client-side script files generated from server-side script now appear in Solution
Explorer. The Script Explorer window is no longer needed and has been removed.
For more information, see How to: View Script Documents.
o Breakpoints set in server-side script files are automatically mapped to
corresponding breakpoints in client-side script files. For more information, see
How to: Set Breakpoints in Script.
o Easy attach to script processes. For more information, see How to: Attach to
Script.
• Improvements to the Debugger Automation model.

Improvements to Tracepoints, Modules Window, Exception Settings, and symbol path


manipulation.

• Better function evaluation.

Improvements to function evaluation detection. Function evaluation now aborts if the


debugger detects evaluation is waiting for a frozen thread.

Visual Studio Debugger


How to: Set Up Remote Debugging

This topic applies to:

Edition Visual Basic C# C++ Web Developer


Express
Standard
Pro and Team

Table legend:

Applies
Does not apply
Command or commands hidden by default

To enable remote debugging, you can do one of two things:

• Install the Remote Debugging Monitor (msvsmon.exe) on the remote computer and start
it when you begin debugging.
• Run the Remote Debugging Monitor remotely from a share.

Running the Remote Debugging Monitor from a file share is the easiest way to enable
remote debugging. Visual Studio installs msvsmon.exe into these directories:

Install path\Microsoft Visual Studio 9.0\Common7\IDE\Remote Debugger\x86

Install path\Microsoft Visual Studio 9.0\Common7\IDE\Remote Debugger\x64

Install path\Microsoft Visual Studio 9.0\Common7\IDE\Remote Debugger\ia64


The IA64 components are available only with Visual Studio Team System.

When you install Visual Studio on a 64-bit operating system, remote debugging components for
both 64-bit and x86 are installed.

When you install Visual Studio on an x86 operating system, remote debugging components for
x86 are installed by default. 64-bit debugging components are installed if you choose the
appropriate option during installation.

When you install the Remote Debugging Monitor on an x86 operating system, only the x86
remote debugging components are installed; there is no option for installing 64-bit components.

By sharing out the Remote Debugger directory on the Visual Studio computer, you can run
msvsmon.exe on the remote computer.

The following debugger features do not work when the Remote Debugging Monitor is run from
a share:

• Stepping into an XML Web service (manual attach is still possible).


• Automatically debugging a ASP.NET Web application (again, manual attach is still
possible).

As an alternative to running from a share, you can use the Visual Studio 2005 Remote Debugger
CD to install the necessary remote debugging components on the remote computer. This
installation provides access to all remote debugging features.

When you run the Remote Debugger installation on an x86 operating system, only the x86
remote debugging components are installed; there is no option for installing 64-bit components.
If you run it on a 64-bit operating system, both x86 and 64-bit components are installed.

For certain debugging scenarios, you must install additional components.

To install remote debugging components

1. The Remote Debugger is available on the last disc of your Visual Studio installation set.
Insert this disc in the remote computer.

For example, if you have four discs in your installation set, insert disc 4 in the remote
computer. If you have a DVD instead of a CD, insert the DVD.

2. In Windows Explorer, open the CD/DVD. Locate the Remote Debugger folder (on the
CD) or vs/Remote Debugger (on the DVD).
3. In the Remote Debugger folder, open the subfolder that matches your operating system
(x86, x64, or IA64).
4. Start the copy of rdbgsetup.exe located in that subfolder, and follow the instructions to
complete setup.
If you prefer, you can install the remote debugging components by copying the files
manually. See Remote Debugging Components for a list of required components and
their install locations.

Visual Studio includes separate versions of the Remote Debugging Monitor for 32-bit
and 64-bit operating systems. If you use rdbgsetup.exe, the Remote Components Setup
will automatically install the correct version of the Remote Debugging Monitor. If you
decide to copy the files manually, you must make sure that you have copied the correct
version.

5. After you have installed the remote debugging components, you must make sure that you
have the required permissions to debug a program on the remote computer. See Remote
Debugging Permissions for a list of required permissions.

Configuring the Windows Firewall

The Windows Firewall must be configured to enable remote debugging. When you start remote
debugging for the first time, Visual Studio performs the necessary configuration on the Visual
Studio host computer. Similarly, when you run the Remote Debugging Monitor on a remote
computer for the first time, the Remote Debugging Monitor configures the Windows Firewall on
that end.

In Windows XP, this configuration is transparent and automatic; however, in Windows Vista, the
new security model requires that you grant permission before the software can configure the
firewall. This permission is granted through the User Access Control dialog box. For a
description of the new security model and User Access Control (UAC), see The Windows Vista
Security Model.

When the Remote Debugging Monitor has to configure the Windows Firewall on the remote
computer, the User Access Control dialog box appears on the remote computer. If the remote
computer is not visible, you may not realize that the User Access Control dialog box has
appeared on its monitor. In that case, you may mistakenly believe that remote debugging has
stopped responding. In reality, the Remote Debugging Monitor is just waiting for someone to
grant UAC permission on the remote computer.

One way to avoid this problem is to preconfigure the firewall on the remote computer by using
the Remote Debugger Configuration Wizard.

It is highly unlikely that you will ever have to configure the Windows Firewall manually. If you
do have to configure it manually, first see How to: Manually Configure the Windows XP
Firewall for Remote Debugging or How to: Manually Configure the Windows Vista Firewall for
Remote Debugging.

To configure the Windows Firewall by using the Remote Debugger


Configuration Wizard
1. Make sure that the remote debugging components have been installed on the computer.
2. Click Start, point to All Programs, point to Visual Studio 9.0, and then click Visual
Studio Remote Debugger Configuration Wizard.
3. Click Start, point to All Programs, point to Visual Studio 9.0, and then click Remote
Debugger.
4. Follow the instructions in the Remote Debugger Configuration Wizard.

Enabling Web Server Debugging

To enable Web server debugging on Windows Vista or Windows XP SP2

• To enable Web server debugging on Windows Vista or Windows XP SP2, you have to
perform some additional steps:
o For Windows Vista, see How to: Enable Web Server Debugging on Windows
Vista.
o For Windows XP SP2, see How to: Enable Web Server Debugging on Windows
XP SP2.

Starting Remote Debugging

To start remote debugging

1. Make sure that you have the necessary remote debugging permissions on the remote
computer. For more information, see Remote Debugging Permissions.
2. For remote debugging other than SQL, make sure that you are running the Remote
Debugging Monitor on the remote computer. For more information, see How to: Run the
Remote Debugging Monitor.

When you are debugging SQL, the Remote Debugging Monitor will start automatically
during debugging.

3. Start Visual Studio on the debugger host.


4. Use Visual Studio to attach to a program that you want to debug on the remote computer,
or start a program that you want to debug on the remote computer. For more information,
see How to: Attach to a Running Process.

Visual Web Developer


Walkthrough: Debugging Web Pages in Visual Web Developer

Visual Web Developer provides you with tools to help track down errors in your ASP.NET Web
pages. In this walkthrough, you will work with the debugger, which allows you to step through
the page's code line by line and examine the values of variables.
In the walkthrough, you will create a Web page that contains a simple calculator that squares a
number. After creating the page (which will include a deliberate error), you will use the
debugger to examine the page as it is running.

Tasks illustrated in this walkthrough include:

• Setting breakpoints.
• Invoking debugger from a Web Forms page in a file system Web site.

Prerequisites

In order to complete this walkthrough, you will need:

• Visual Web Developer and the .NET Framework.

You should also have a general understanding of working in Visual Web Developer. For an
introduction to Visual Web Developer, see Walkthrough: Creating a Basic Web Page in Visual
Web Developer.

Creating the Web Site and Page

In the first part of the walkthrough, you will create a page that you can debug.

If you have already created a Web site in Visual Web Developer (for example, by working with
the topic Walkthrough: Creating a Basic Web Page in Visual Web Developer ), you can use that
Web site and skip to "Adding Controls to Debug" later in this walkthrough. Otherwise, create a
new Web site and page by following these steps.

To create a file system Web site

1. Open Visual Web Developer.


2. On the File menu, click New Web Site.

The New Web Site dialog box appears.

3. Under Visual Studio installed templates, click ASP.NET Web Site.


4. In the Location box, click File System and then type the name of the folder where you
want to keep the pages of your Web site.

For example, type the folder name C:\WebSites.

5. In the Language list, click the programming language that you prefer to work in.

The programming language you choose will be the default for your Web site. However,
you can use multiple languages in the same Web application by creating pages and
components in different programming languages. For information on creating
components using different languages, see Shared Code Folders in ASP.NET Web Sites.

6. Click OK.

Visual Web Developer creates the folder and a new page named Default.aspx.

Creating a Page to Debug

You will begin by creating a new page. For this walkthrough, it is important that you create a
new page as specified in the following procedure.

To add a page to the Web site

1. Close the Default.aspx page.


2. In Solution Explorer, right-click the name of your Web site (for example, C:\WebSite)
and choose Add New Item.
3. Under Visual Studio installed templates, choose Web Form.
4. In the Name box, type DebugPage.aspx.
5. From the Language list, choose the programming language you prefer to use.
6. Be sure that the Place code in separate file check box is cleared.

In this walkthrough, you are creating a single-file page with the code and HTML in the
same page. The code for ASP.NET pages can be located either in the page or in a
separate class file. To learn more about keeping the code in a separate file, see
Walkthrough: Creating a Basic Web Page with Code Separation in Visual Web
Developer .

7. Click Add.

Visual Web Developer creates the new page and opens it in Source view.

You can now add some controls to the page and then add code. The code will be simple, but
enough to allow you to add breakpoints later.

To add controls and code for debugging

1. Switch to Design view, and then from the Standard folder of the Toolbox, drag the
following controls onto the page and set their properties as indicated:

Control Properties
ID: CaptionLabel
Label
Text: (empty)
ID: NumberTextBox
TextBox
Text: (empty)
ID: SquareButton
Button
Text: Square
ID: ResultLabel
Label
Text: (empty)
Note:
For this walkthrough, the layout of the page is not important.

2. Double-click the Button control to create a Click handler for it.


3. Add logic to the Click handler to call a function called Square to square the number
entered by the user. The handler might look like the following example.
Note:
The code example deliberately does not include error checking.
4. Visual Basic
5. Sub SquareButton_Click(ByVal sender As Object, _
6. ByVal e As System.EventArgs)
7. Dim number As Integer
8. Dim result As Integer
9. number = CInt(NumberTextBox.Text)
10. result = Square(number)
11. ResultLabel.Text = CStr(number) & " squared is " & CStr(result)
12. End Sub
13. C#
14. protected void SquareButton_Click(object sender, System.EventArgs e)
15. {
16. int number, result;
17. number = System.Convert.ToInt32(NumberTextBox.Text);
18. result = Square(number);
19. ResultLabel.Text = NumberTextBox.Text +
20. " squared is " + result.ToString();
21. }
22. Create the function that squares the number. Include a bug in the code to add the number
to itself instead of multiplying it. The code might look like the following example.

Visual Basic

Function Square(number As Integer) As Integer


Square = number + number
End Function

C#

int Square(int number )


{
int Square;
Square = number + number;
return Square;
}

You can also add code to the page that will change the text of the label depending on whether
this is the first time the page is running.

To change the caption Label control

1. In Design view, double-click the design surface (not a control) to create a Page_Load
event handler.
2. Set the text of the Caption Label control to Enter a number: if this is the first time the
page is running, or Enter another number: otherwise. The handler will look like the
following code example.

Visual Basic

Sub Page_Load(ByVal sender As Object, ByVal e as System.EventArgs)


If Page.IsPostBack = False Then
CaptionLabel.Text = "Enter a number: "
Else
CaptionLabel.Text = "Enter another number: "
End If
End Sub

C#

if(Page.IsPostBack == false)
{
CaptionLabel.Text = "Enter a number: ";
}
else {
CaptionLabel.Text = "Enter another number: " ;
}

Testing the Page

To make sure the page is working, run it in its current state.

To run the page

1. Save the page.


2. Press CTRL+F5 to run the page.
3. Enter the number 3 and press the Square button.

Note that the result is incorrect, because there is a bug in the program. The correct result
is 9.
4. Close the browser.

Debugging the Page

In this part of the walkthrough, you will use the debugger to examine the page code line by line
as it is running, add breakpoints to the code, and then run the page in Debug mode.

You will start by setting breakpoints in your code. A breakpoint is a line in your code where
execution stops and the debugger is invoked.

To set breakpoints

1. Switch to Source view.


2. Right-click the following line, choose Breakpoint, and then choose Insert Breakpoint.
Note:
You can toggle breakpoints by pressing F9.
3. Visual Basic
4. If Page.IsPostBack = False Then
5. C#
6. if(Page.IsPostBack == false)
7. Set another breakpoint on the following line of the SquareButton_Click handler:

Visual Basic

result = Square(number)

C#

result = Square(number);
Note:
You cannot set a breakpoint on a statement that declares a variable.

With at least one breakpoint set, you are ready to run the debugger.

To run the debugger

1. From the Debug menu, choose Start Debugging (or press F5) to run the page in debug
mode.

If you have never run the debugger before, your application probably is not configured to
support debugging. By default, debugging is turned off in applications both for
performance (pages run more slowly in the debugger) and for security reasons. Visual
Web Developer displays a message telling you what it must do to enabled debugging.

The switch to enable debugging is stored as a setting in the Web.config file, which
maintains various site-specific configuration options. If the Web.config file does not
exist, Visual Web Developer will both create the file and make the appropriate debugger
setting.

If the Web.config file already exists but debugging is not enabled, you will see a slightly
different message telling you that Visual Web Developer will modify the Web.config file.

2. If you see the message telling you that debugging has not been enabled, click OK to
enable debugging.

In Visual Web Developer, the designer changes to debug mode displaying the code for
your page and some debugger windows.

The debugger runs your page line by line. When the debugger gets to the line with the
breakpoint, it stops and highlights the line.

Because the breakpoint is in the Page_Load handler, the page has not finished processing
yet. The browser is open, but the page is not yet displayed.

3. In the Debug menu, click Windows, click Watch, and then click Watch 1.
Note:
If you are using Visual Web Developer Express Edition, the debugger offers only a single
Watch window.
4. This opens a Watch window, where you can specify the values you want to track.
5. In the editor, right-click the IsPostBack portion of the Page.IsPostBack expression, and
then click Add Watch.

This adds the expression to the Watch window and displays the current value of the
property (false) is displayed in the Value column. If you prefer, you can type the name of
a variable or property in the Name column of the Watch window.

6. From the Debug menu, choose Continue to continue execution, or press F5.

The Continue command tells the debugger to proceed until it gets to the next breakpoint.
The Page_Load event handler finishes processing and the page is displayed in the
browser.

7. Enter the value 2 into the text box and click the Square button.

The debugger is displayed again, with the breakpoint on the line in the Page_Load
handler. This time, the Watch window shows you that the value of Page.IsPostBack is
true.

8. Press F5 again to continue.

The debugger processes the Page_Load handler and enters the SquareButton_Click
handler, where it stops on the second breakpoint you set.
9. In the Debug menu, click Windows and then click Locals.

This opens the Locals window, which displays the values of all variables and objects that
are in scope at the current line being executed. The Locals window provides an
alternative way for you to view these values, with the advantage that you do not have to
explicitly set a watch on the elements, but with the disadvantage that the window might
contain more information than you want to see at once.

In the Locals window, you see that the value of number is 2 and the value of result is 0.

Note:
You can also see the value of any variable in the program by holding the mouse pointer
over it.

10. In the Value column of the Locals window, right-click the line for the number variable
and select Edit value. Edit the value of the number variable and change it to 5.

The value 2 for the variable number is not a good test of the program, because adding and
squaring 2 both result in 4. Therefore, while the program is running, you can change the
value of this variable.

11. From the Debug menu, choose Step Into to step into the Square function, or press F11.

The Step Into command causes the debugger to execute a line and then stop again.

12. Continue stepping by pressing F11 until you reach the following line of code.

Visual Basic

ResultLabel.Text = CStr(number) & " squared is " & CStr(result)

C#

ResultLabel.Text = NumberTextBox.Text +
" squared is " + result.ToString();

The debugger walks through your code line by line. When the debugger executes the
Square function, you can use the Locals window to check the data passed to the function
(number) and the return value of the function (Square).

13. In the Debug menu, click Windows and then Immediate.

The Immediate window allows you to execute commands. You can use the window to
evaluate expressions (for example, to get the value of a property).

14. In the Immediate window, type the following expression and press Enter.
15. ? NumberTextBox.Text
The question mark (?) is an operator in the Immediate window that evaluates the
expression following it. In this example, you are evaluating the Text property of the
NumberTextBox control on the page. You can evaluate any variable, object property, or
expression that combine these, using the same syntax that you would use in code.

16. In the Immediate window, type the following and press Enter:
17. NumberTextBox.Text = "5"

In addition to evaluating expressions, the Immediate window allows you to change


variables or properties

18. Press F5 to continue running the program.

When the page appears, it displays the result of passing 5 to the Square function. In
addition, the text in the text box has been changed to 5.

The result you see — 10 — is not correct, since 10 is not the square of 5. You can now fix the
bug.

To fix the bug and test again

1. Switch from the browser to Visual Web Developer.


Note:
Do not close the browser window.
2. In the Square function, change the "+" operator to the "*" operator.

Because the code is not currently running (the page has finished processing), you are in
edit mode and can make permanent changes.

3. Press CTRL+S to save the page.


4. From the Debug menu, choose Delete All Breakpoints so that the page will not stop each
time you run it.
Note:
You can also clear breakpoints by pressing CTRL+SHIFT+F9.
5. Switch to the browser window.
6. Enter 5 in the text box and click the button.

This time, when you run the page and enter a value, it is squared correctly. The
temporary changes you made earlier, such as changing the Text property of the
NumberTextBox control, have not been persisted, because they applied only when the
page was running the last time.

7. Close the browser to stop the debugger.

Next Steps
The debugger includes additional features to help you work with your code. In addition, you
might want to learn about techniques for handling error conditions and ways in which you can
monitor page processing at run time. For example, you might want to explore tracing. For
details, see Walkthrough: Using Tracing in Visual Web Developer to Help Find Web Page
Errors.

Visual Studio Debugger


Debugging ASP.NET and AJAX Applications

Debugging ASP.NET Web applications is similar to debugging a Windows Form or any other
Windows application because both kinds of applications involve controls and events. However,
there are also basic differences between the two kinds of applications:

• Keeping track of state is more complex in a Web application.


• In a Windows application, the code to be debugged is mostly in one location; in a Web
application, the code can be on the client and on the server. While ASP.NET code is all
on the server, there might also be JavaScript or Visual Basic code on the client.

In This Section
Preparing to Debug ASP.NET

Describes the steps that are required to enable debugging of ASP.NET applications.

Debugging Web Applications and Services

Discusses how to debug a ASP.NET application, including AJAX-enabled script


applications, and XML Web services.

Visual Studio Debugger


Preparing to Debug ASP.NET

This topic applies to:

Edition Visual Basic C# C++ Web Developer


Express
Standard
Pro and Team

Table legend:

Applies
Does not apply
Command or commands hidden by default.

This section describes how to set up Visual Studio to debug an ASP.NET or WCF application.
In This Section
ASP.NET Debugging: System Requirements

Describes the operating system requirements for debugging ASP.NET or WCF Web
applications by using Visual Studio.

Limitations on WCF Debugging

Explains limits about how to debug WCF Web applications by using Visual Studio.

How to: Enable Debugging for ASP.NET Applications

Discusses setting debug mode for an ASP.NET application. Information includes a


description of Web.config files, suggestions for editing the file, sample code, and the
behavior of hierarchical configuration files.

How to: Debug Web Applications on a Remote Server

Lists prerequisites for debugging a Web application on a remote server.

How to: Configure IIS on Windows Server 2003

Discusses special configuration steps needed for debugging system requirements for
debugging ASP.NET on Windows Server 2003.

How to: Debug a Self-Hosted WCF Service

Describes steps for debugging a WCF service that is not hosted on IIS or the ASP.NET
Development Server.

Visual Studio Debugger


How to: Configure IIS on Windows Server 2003

This topic applies to:

Edition Visual Basic C# C++ Web Developer


Express
Standard
Pro and Team

Table legend:

Applies
Does not apply
Command or commands hidden by default.
When you are debugging an application on Windows Server 2003, the user account that creates
the application pool must be in the IIS_WPG group. Otherwise, you will not be able to debug the
application, even if the user is an Administrator on the computer.

To configure IIS on Windows Server 2003

1. Click Start and point to All Programs.


2. Click Administrative Tools, and then click Internet Information Services.
3. Right-click your computer name in the left pane, and then click Security.
4. On the first screen of the IIS Security Lockdown Wizard, click Next.
5. Verify that HTTP is set to Automatic, and click Next.
6. In the Request Handlers list, check ASP.NET, and each instance of <Microsoft.NET
Framework install directory>\aspnet_isapi.dll.
7. Click Next.
8. Click Finish to complete the wizard.

Visual Studio Debugger


How to: Run the Worker Process Under a User Account

This topic applies to:

Edition Visual Basic C# C++ Web Developer


Express
Standard
Pro and Team

Table legend:

Applies
Does not apply
Command or commands hidden by default.

To set up your computer so that you can run the ASP.NET worker process (aspnet_wp.exe or
w3wp.exe) under a user account, follow these steps.

Procedure

To run aspnet_wp.exe under a user account

1. Open the machine.config file, located on your computer in the CONFIG folder under the
path where you installed the runtime.
2. Find the <processModel> section and change the user and password attributes to the
name and password of the user account you want aspnet_wp.exe to run under.
3. Save the machine.config file.
4. On Windows Server 2003, IIS 6.0 is installed by default. The corresponding worker
process is w3wp.exe.To run in IIS 5.0 mode with aspnet_wp.exe as the worker process,
you must follow these steps:
1. Click Start, click Administrative Tools and then choose Internet Information
Services.
2. In the Internet Information Services dialog box, right-click the Web Sites folder
and choose Properties.
3. In the Web Sites Properties dialog box, choose Service.
4. Select Run WWW service in IIS5.0 isolation mode.
5. Close the Properties dialog box and Internet Services Manager.
5. Open a Windows Command Prompt and reset the server by running:
6. iisreset

— or —

net stop iisadmin /y


net start w3svc

7. Locate the Temporary ASP.NET Files folder, which should be in the same path as the
CONFIG folder. Right-click the Temporary ASP.NET Files folder and choose
Properties on the shortcut menu.
8. In the Temporary ASP.NET Files Properties dialog box, click the Security tab.
9. Click Advanced.
10. In the Advanced Security Settings for Temporary ASP.Net Files dialog box, click Add.

The the Select User, Computer, or Group dialog box appears.

11. Type the user name in the Enter the object name to select box, and then click OK. The
user name must follow this format: DomainName\UserName.
12. In the Permission Entry for Temporary ASP.NET Files dialog box, give the user Full
Control, and then click OK to close the Entry for Temporary ASP.NET Files dialog box.
13. A Security dialog box will appear, and asks if you really want to change the permissions
on a system folder. Click Yes.
14. Click OK to close the Temporary ASP.NET Files Properties dialog box.

Visual Studio Debugger


How to: Debug Web Applications on a Remote Server

This topic applies to:

Edition Visual Basic C# C++ Web Developer


Express
Standard
Pro and Team

Table legend:
Applies
Does not apply
Command or commands hidden by default.

With the Visual Studio debugger, you can debug a Web application transparently on the local
computer or a remote server. This means that the debugger functions the same way and allows
you to use the same features on either computer. For remote debugging to work correctly,
however, there are some prerequisites.

• Visual Studio remote debugging components must be installed on the server you want to
debug. For more information, see Setting Up Remote Debugging.
• By default, the ASP.NET worker process runs as an ASPNET user process. As a result,
you must have Administrator privileges on the computer where ASP.NET runs to debug
it. The name of the ASP.NET worker process varies by debug scenario and version of
IIS. For more information, see How to: Find the Name of the ASP.NET Process.
• In Visual C++, the project must be set up to connect by using DCOM instead of TCP/IP.
To set this property, follow these steps:

To enable Visual C++ projects to connect through DCOM

1. Open the <Project>Property Pages dialog box.


2. Open the Configuration Properties node if not already opened.
3. Select the Debugging node under Configuration Properties.
4. Choose Remote Windows Debugger under Debugger to launch.
5. Choose Remote with Windows authentication under Connection.

For more information, see Project Settings for a C or C++ Debug Configuration.

Visual Studio Debugger


How to: Enable Debugging for ASP.NET Applications

This topic applies to:

Edition Visual Basic C# C++ Web Developer


Express
Standard
Pro and Team

Table legend:

Applies
Does not apply
Command or commands hidden by default.
To enable debugging, you must enable it in both the Project Properties page and in the
application's web.config file.

Note:
The dialog boxes and menu commands you see might differ from those described in Help
depending on your active settings or edition. To change your settings, choose Import and Export
Settings on the Tools menu. For more information, see Visual Studio Settings.

To enable ASP.NET debugging in the project properties (Visual Basic/C#)

1. In Solution Explorer, right-click the name of a Web project and select Property Pages.

The <Project> Property Pages appears.

2. Click the Web tab.


3. Under Debuggers, select the ASP.NET check box.

To enable debugging in the web.config file

1. Open the web.config file by using any standard text editor or XML parser.
1. You cannot access the file remotely by using a Web browser, however. For
security reasons, ASP.NET configures Microsoft IIS to help prevent direct
browser access to Web.config files. If you try to access a configuration file by
using a browser, you will get HTTP access error 403 (forbidden).
2. Web.config is an XML file, and so contains nested sections marked by tags. The
following example shows a typical Web.config file. Modify the file by following these
steps:
1. Locate the <compilation> tag. This marks the beginning of the <compilation>
section.
2. Inside the <compilation> tag, you will create the debug attribute. In the following
example , debug is the second attribute that is specified in the <compilation> tag,
but the order is not important.
3. Attributes are case-sensitive, therefore make sure that you specify "debug", not
"Debug" or "DEBUG."
4. Set debug to true, as shown in the following code example.
3. If you do not set the debug attribute to true and try to launch a debugging session, a
dialog box will appear, offering to create a web.config file with the attribute set. Accept,
and continue to debug.

Example
<configuration>
<system.web>
<compilation defaultLanguage="VB"
debug="true"
numRecompilesBeforeAppRestart="15">
<compilers>
<compiler language="VB;VBScript"
extension=".cls"
type="Microsoft.VisualBasic.VBCodeProvider,system,
Version=1.0.5000.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089" />
< compiler language="C#;Csharp"
extension=".cs"
type="Microsoft.CSharp.CSharpCodeProvider,system,
Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</compilers>

<assemblies>
"" <add assembly="ADODB" />
<add assembly="*" />
</assemblies>

<namespaces>
<add namespace="System.Web" />
<add namespace="System.Web.UI" />
<add namespace="System.Web.UI.WebControls" />
<add namespace="System.Web.UI.HtmlControls" />
</namespaces>

</compilation>
</system.web>
</configuration>
Robust Programming

ASP.NET automatically detects any changes to Web.config files and applies the new
configuration settings. You do not have to restart the computer or restart the IIS server for
changes to take effect.

A Web site can contain multiple virtual directories and subdirectories, and Web.config files may
exist in each one. ASP.NET applications inherit settings from Web.config files at higher levels in
the URL path. Hierarchical configuration files allow you to change settings for several ASP.NET
applications at the same time, such as for all applications below it in the hierarchy. However, if
debug is set in a file lower in the hierarchy, it will override the higher value.

For example, you could specify debug="true" in www.microsoft.com/aaa/Web.config, and any


application in the aaa folder or in any subfolder of aaa will inherit that setting. So if your
ASP.NET application is at www.microsoft.com/aaa/bbb, it will inherit that setting, as will any
ASP.NET applications in www.microsoft.com/aaa/ccc, www.microsoft.com/aaa/ddd, and so on.
The only exception is if one of those applications overrides the setting by means of its own lower
Web.config file.

Enabling debug mode will greatly affect the performance of your ASP.NET application.
Remember to disable debug mode before you deploy a release application or conduct
performance measurements.

Visual Studio Debugger


Debugging Web Applications and Services
This section explains how to debug several types of Web applications and Web services.

In This Section
How to: Debug Web Applications and Web Services

Describes how to debug an ASP.NET project still under development.

Debugging Deployed Web Applications and Web Services

Explains how to debug an already-deployed ASP.NET Web application.

Client-Side Script Debugging

Discusses testing scripts and client-side scripts in ASP.NET pages.

Walkthrough: Debugging a Web Form

Illustrates how to debug an ASP.NET Web application.

How to: Debug ASP.NET Exceptions

Explains how to deal with exceptions that occur while you debug ASP.NET applications.

Debugging XML Web Services

Illustrates how to debug an XML Web service.

Visual Studio Debugger


How to: Debug Web Applications and Web Services

This topic applies to:

Edition Visual Basic C# C++ Web Developer


Express
Standard
Pro and Team

Table legend:

Applies
Does not apply
Command or commands hidden by default.

ASP.NET is the primary technology for developing Web applications in Visual Studio. The
Visual Studio debugger provides powerful tools for debugging ASP.NET Web applications
locally or on a remote server. This topic describes how to debug an ASP.NET project during
development. For information about how to debug a ASP.NET Web application already
deployed on a production server, see Debugging Deployed Web Applications and Web Services.

To debug an ASP.NET application:

• You must have required permissions. For more information, see ASP.NET Debugging:
System Requirements.
• ASP.NET debugging must be enabled in Project Properties.
• The configuration file of your application (Web.config) must be set to debug mode.
Debug mode causes ASP.NET to generate symbols for dynamically generated files and
enables the debugger to attach to the ASP.NET application. Visual Studio sets this
automatically when you start to debug, if you created your project from the Web projects
template.
• For more information, see How to: Enable Debugging for ASP.NET Applications.

To debug a Web application during development

1. On the Debug menu, click Start to begin debugging the Web application.

Visual Studio builds the Web application project, deploys the application if necessary,
starts the ASP.NET Development Server if you are debugging locally, and attaches to the
ASP.NET worker process.

2. Use the Debugger to set and clear breakpoints, step, and perform other debugging
operations, as you would for any application.

For more information, see Debugger Roadmap.

3. On the Debug menu, click Stop Debugging to end the debugging session, or, on the File
menu in Internet Explorer, click Close.
4. Visual Studio Debugger
5. Debugging Deployed Web Applications and Web Services
6. This topic applies to:
Edition Visual Basic C# C++ Web Developer
Express
Standard
Pro and Team
7. Table legend:
Applies
Does not apply
Command or commands hidden by default.
8. If you need to debug a Web application that is running on a production server, this should
be done with caution. If you attach to the ASP.NET worker process for debugging and hit
a breakpoint, for example, all managed code in the worker process halts. Halting all
managed code in the worker process can cause a work stoppage for all users on the
server. Before you debug on a production server, consider the potential impact on
production work.
9. To use Visual Studio to debug a deployed application, you must attach to the ASP.NET
worker process and make sure that the debugger has access to symbols for the
application. You must also locate and open the source files for the application. For more
information, see Managing Symbols and Source Code, How to: Find the Name of the
ASP.NET Process, and ASP.NET Debugging: System Requirements.
Note:
Many ASP.NET Web applications reference DLLs that contain business logic or other useful
code. Such a reference automatically copies the DLL from your local computer to the \bin folder
of the Web application's virtual directory. When you are debugging, remember that your Web
application is referencing that copy of the DLL and not the copy on your local computer.
10. The process for attaching to the ASP.NET worker process is the same as attaching to any
other remote process. When you are attached, if you do not have the correct project open,
a dialog box appears when the application breaks. This dialog box asks for the location of
the source files for the application. The file name that you specify in the dialog box must
match the file name specified in the debug symbols on the Web server. For more
information, see Attaching to Running Processes.

Visual Studio
Debugging Client-Side Scripts

The Microsoft Visual Studio .NET debugger provides you with a comprehensive debugging
environment for testing and correcting errors in your Web document scripts. You can use the
Visual Studio .NET debugger to test scripts written in Microsoft Visual Basic Scripting Edition
(VBScript) and Microsoft JScript.

You can use the Visual Studio .NET debugger to debug client-side scripts in an ASP.NET page.
Client-side scripts consist of statements that appear on the HTML page. Microsoft Internet
Explorer executes the script when the document is loaded or in response to an event (such as a
button click).

Setting a Breakpoint in Client-Side Script

If you want to set a breakpoint in client-side script, you cannot just set the breakpoint in the
project .aspx file. The .aspx file is a server-side document, and breakpoints set there are not
translated to the client-side document. Instead, you can set a client-side breakpoint using either
of the following methods.

To set a breakpoint in client-side script

• Write all the client-side script in a single function and set a function breakpoint on that
function.

–or–
• Open the client-side script from the Running Documents window and set the breakpoint
there.

Enabling Script Debugging

Note Script debugging is disabled in Internet Explorer by default. To debug a client-side script
application, you must first enable script debugging in Internet Explorer.

To enable script debugging in Internet Explorer 5.5 or later

1. From the Tools menu, choose Internet Options.


2. In the Internet Options dialog box, choose the Advanced tab.
3. In the Browsing category, clear the Disable script debugging check box.
4. Click OK.

In addition, to hit breakpoints in client-side script, a cookie called ASPCLIENTDEBUG cookie


must be set. If this cookie is not set automatically, you can set it manually using the following
procedure.

To manually set ASPCLIENTDEBUG cookie

1. Create an HTML text file that contains the following code:


2. <html>
3. <head>
4.
5. <script language="JavaScript">
6.
7. function set ()
8. {
9. var expdate = new Date();
10. expdate.setMonth(expdate.getMonth()+6);
11. alert("setting cookie \""+form1.txtName.value+"\"
to \""+form1.txtValue.value+"\"");
12. setCookie(form1.txtName.value, form1.txtValue.value, expdate);
13. }
14.
15. function get ()
16. {
17. alert("getting cookie \""+form1.txtName.value+"\"");
18. var c = getCookie(form1.txtName.value);
19. alert( "cookie = "+c );
20.
21. form1.txtValue.value = c;
22. }
23.
24. function getCookie (sCookieName)
25. {
26. var sName=sCookieName+"=", ichSt, ichEnd;
27. var sCookie=document.cookie;
28.
29. if ( sCookie.length && ( -1 != (ichSt =
sCookie.indexOf(sName)) ) )
30. {
31. if (-1 == ( ichEnd = sCookie.indexOf(";",ichSt+sName.length) )
)
32. ichEnd = sCookie.length;
33. return unescape(sCookie.substring(ichSt+sName.length,ichEnd));
34. }
35.
36. return null;
}

function setCookie (sName, vValue)


{
var argv = setCookie.arguments, argc = setCookie.arguments.length;
var sExpDate = (argc > 2) ? "; expires="+argv[2].toGMTString() : "";
var sPath = (argc > 3) ? "; path="+argv[3] : "";
var sDomain = (argc > 4) ? "; domain="+argv[4] : "";
var sSecure = (argc > 5) && argv[5] ? "; secure" : "";
document.cookie = sName + "=" + escape(vValue,0) + sExpDate + sPath +
sDomain + sSecure + ";";
}

function deleteCookie (sName)


{
document.cookie = sName + "=" + getCookie(sName) + "; expires=" + (new
Date()).toGMTString() + ";";
}

</script>

</head>

<body>

<form name=form1>
cookie name:<input type="text" name="txtName" value="ASPCLIENTDEBUG"><p>
cookie value:<input type="text" name="txtValue" value="doesn't matter"><p>
<input type="button" value="Set Cookie" onClick="set()">
<input type="button" value="Get Cookie" onClick="get()">
</form>
</body>
</html>

1. Save the file as cookie.html.


2. Copy the file to

c:\inetput\wwwroot

3. In the Internet Explorer Address box, type:

http://localhost/cookie.html

4. In the http://localhost/cookie.html window, click the Set Cookie button.

Better Error Messages For Script Debugging


Visual Studio .NET 2003 provides enhanced error messages for common script debugging
problems. You will normally not see these messages unless you attach to Internet Explorer
manually instead of having the debugger launch Internet Explorer automatically. If you
encounter a problem, use the following procedure to manually attach and get more information.

To manually attach

1. From the Debug menu, choose Processes.

The Processes dialog box appears.

2. If you have already started debugging, go to the list of Debugged Processes. Select the
process you are debugging and click Detach.
3. In the Available Processes box, find Internet Explorer (iexplore.exe), select it, and click
Attach.
4. In the Attach to Process dialog box, under Choose the program types that you want to
debug, select only Script.
5. Click OK.
6. At this point, an error message box may appear. If it does, click the Help button to get
more information.

Visual Studio

Debugging Client-Side Scripts in a Web Page

Using the Visual Studio .NET debugger, you can perform the following tasks when debugging
client-side script in a Web page:

• View the source code of the Web page (.htm, .html, .asp, .aspx) that you are
debugging.
• Control the pace of script execution with breakpoints and stepping.
• View and change variable and property values with several debugging
windows including the Command window and Watch window.
• View and control script flow with the Call Stack window.

Note To debug script you must enable script debugging in Internet Explorer.

Viewing Source

When you work with the Microsoft Visual Studio .NET debugger, you see the script that you are
debugging in a read-only editor in the IDE. You cannot change the text in the window —
documents are read-only while you are debugging. However, you can save the document under a
new name, then open the document and modify it.
Controlling Program Execution

To control program execution, you set breakpoints, which are places where the script should
pause and call the debugger. When you set breakpoints, the line containing the breakpoint is
highlighted in the editor.

After setting a breakpoint, you run the document containing the script. When execution reaches
the first breakpoint, the script pauses and starts the debugger. The current line is marked in the
editor with a yellow box.

After reaching a breakpoint, you can execute, or step into, individual lines in your script. As you
step through lines, the script executes and you can see the effect of each line.

If you reach a point in your script that calls another procedure (a function, subroutine) you enter
(step into) the procedure or run (step over) it and stop at the next line. At any point, you can
jump to the end (step out) of the current procedure and proceed to the next breakpoint.

Viewing and Changing Values

While debugging, you can view and change the values of variables or properties. Because you
are making changes directly to a running script, you can affect the way that the script executes by
changing values in it. After changing values, you can continue with the script and see the effect
of your change.

To view and change values, you use the Immediate window. You can evaluate any expression in
the window and can enter script commands and see their effect. You can enter commands in the
language of the script currently executing.

Viewing and Controlling Program Flow

The Call Stack window allows you to trace the procedures and functions that are currently
executing. While debugging, you can view the flow of control from procedure to procedure. You
can also select a procedure in the call stack and jump directly to it and then continue running the
script.

Visual Studio

Debugging Client-Side Scripts in Your Application

There are several ways that you can debug the client-side script in your application:

• From Microsoft Internet Explorer


• Using the Running Documents window
• In a Script
• In Response to an Error
Note To debug script you must enable script debugging in Internet Explorer.

From Microsoft Internet Explorer

To debug a client-side script from Microsoft Internet Explorer

1. From the View menu, select Script Debugger and click Open. This
launches the Just-In-Time Debugging dialog box.
2. From Possible Debuggers list in the Just-In-Time Debugging dialog box,
select New Instance of Microsoft Development Environment and click
Yes.
3. In the Attach to Process dialog box, in the Choose the program types
that you want to debug box, select the Script check box and click OK.

To specify that the debugger stop at the first statement of scripts

1. From the View menu, select Script Debugger and click Break at Next
Statement. This launches the Just-In-Time Debugging dialog box.
2. From Possible Debuggers list in the Just-In-Time Debugging dialog box,
select New Instance of Microsoft Development Environment and click
Yes.
3. In the Attach to Process dialog box, in the Choose the program types
that you want to debug box, select the Script check box and click OK.

From now on, when any script is executed, the debugger stops at the first statement of the
script.

Using the Running Documents Window

The Running Documents window shows a list of documents that are currently loaded into the
program you are debugging. For example, in an HTML frameset, the Running Documents
window can show you the pages currently loaded in the browser. You can use the Running
Documents window to open a document and set a breakpoint inside the script code. You can also
use this window to see and debug code that is generated by script on the server and sent to the
client.

In a Script

When writing a script, include a Stop statement (VBScript) or debugger statement (JScript).
When script execution reaches that line, the Visual Studio .NET debugger is launched.

In Response to an Error

If the browser or server encounters a syntax error or run time error in a script, it displays a
message that offers you the opportunity to start the debugger at the line where the error occurred.
Visual Studio

Debugging ASP.NET Web Services

Debugging an XML Web service created with ASP.NET is similar to debugging an ASP.NET
Web application. For more information, see Debugging ASP.NET Web Applications. You can
perform many of the same operations, such as setting breakpoints, stepping through code, and
viewing the state of your program using various debugger windows.

When a managed client calls a managed XML Web service, the Visual Studio .NET debugger
can automatically step between the client and the XML Web service. For details, see Stepping
Into an XML Web Service.

The following sections explain some useful techniques for debugging XML Web services:

• Debugging an XML Web Service on //localhost


• Debugging an XML Web Service on a Remote Server
• Error While Trying To Run Project
• Debugging a Deployed XML Web Service

Debugging an XML Web Service on http://localhost

During development, you may want to debug an XML Web service on http://localhost rather
than a remote server. For more information, see Debugging a Deployed XML Web Service.

To debug an XML Web service during development

1. If you have not already done so, set the debug mode attribute in the
application's Web.config configuration file. For more information, see Debug
Mode in ASP.NET Applications. Debug mode tells ASP.NET to generate
symbols for dynamically generated files and enables the debugger to attach
to the ASP.NET application. (Projects created from the XML Web service
template should have this set automatically.)
2. In Visual Studio .NET, use the <Project> Property Pages to set the project
properties for XML Web service debugging.
3. To start debugging the XML Web service, choose Start from the Debug
menu.

Visual Studio .NET builds the XML Web service project and deploys the application and
its symbol information.

4. Use the debugger to set and clear breakpoints, step, and perform other
debugging operations, as you would for any application. For more
information, see Using the Debugger.
5. To end the debugging session in Visual Studio .NET, choose the Stop
Debugging command on the Debug menu or, in Internet Explorer, choose
Close from the File menu.
Debugging an XML Web Service on a Remote Server

With the Visual Studio .NET debugger, you can debug an XML Web service transparently on
the local machine or a remote server. This means that the debugger functions the same way and
allows you to use the same features on either machine. For remote debugging to work properly,
however, there are some prerequisites.

• Visual Studio .NET remote debugging components must be installed on the


server you want to debug. (For more information, see Setting Up Remote
Debugging.)
• In C/C++, the project must be set up to connect using DCOM rather than
TCP/IP. To set this property, you must open the <Project> Property Pages
dialog box and choose Remote via DCOM for Connection. (For more
information, see Project Settings for a C or C++ Debug Configuration.)
• By default, the ASP.NET process (aspnet_wp.exe for IIS5.0 and IIS 5.1 on
Windows 2000 and Windows XP or w3wp.exe on IIS6 on Windows Server
2003) runs as an ASPNET process. As a result, you must have Administrator
privileges on the machine where ASP.NET runs to debug it.
• The remote server must grant the debugger access. To grant access to a
user, you must add the user to the Administrators group on the server. (If the
ASP.NET worker process is running under your the user's own account, you
can add the user to either the Administrators group or the Debugger Users
group.)

To add a user to the Debugger Users group on a server

1. Log onto the server as Administrator.


2. Right-click My Computer and choose Manage from the shortcut menu.
3. Under System Tools, Local Users and Groups, open the Groups folder.
4. Double-click Debugger Users.
5. In the Debugger Users Properties dialog box, you will see a list of
members. If the user does not appear in the Members list, click the Add
button.
• In the Select Users or Groups dialog box, select the name of the
user you want to add from the list and click Add.

-or-

α. Type the name of the user in the lower box.


β . Click OK.
2. Click OK.
3. You need to restart your computer for the changes to take effect.

For more information about adding users and groups, click the Help button at the top of the
Computer Management console.

Error: Error While Trying To Run Project


If you are not a member of Debugger Users on the remote server, you will get the following
error message when you try to debug:

Error while trying to run project: Unable to start debugging on the Web server.
Access is denied. Check the DCOM configuration settings for the machine debug
manager. Would you like to disable future attempts to debug ASP.NET pages for this
project.

Debugging a Deployed XML Web Service

Sometimes, you may need to debug an XML Web service that is already deployed and running
on a server. To debug a deployed and running XML Web service from Visual Studio .NET, you
must attach to the ASP.NET worker process (aspnet_wp.exe for IIS5.0 and IIS 5.1 on Windows
2000 and Windows XP or w3wp.exe on IIS6 on Windows Server 2003). To attach to the
ASP.NET worker process, follow the steps in this procedure:

To debug a deployed XML Web service

1. From the Debug menu, choose Processes.

The Processes dialog box appears. For more information, see Processes Dialog Box. The
following steps are performed in this dialog box.

2. If the XML Web service is running on a remote server, select the remote
machine.
3. Select Show System Processes.
4. In the Available Processes list, choose the process aspnet_wp.exe or
w3wp.exe.
5. Click the Attach button.
a. In the Attach to Process dialog box, make sure Common Language
Runtime is selected in Choose the program types that you want
to debug.
b. Click OK.
6. At the bottom of the Processes dialog box is a drop-down list box labeled
When debugging is stopped. From this list, you can choose whether to
terminate or detach from the process when you stop debugging. The default
setting is Detach from this process, which resumes all threads in the
process when debugging stops. If you choose Terminate this process, the
aspnet_wp.exe or w3wp.xee process terminates when debugging stops.
Terminating the aspnet_wp.exe or w3wp.exe process will affect all ASP.NET
applications running on the server, so this is not something you want to do in
most cases.
7. Click OK.

The next time that the application breaks, a dialog box appears asking for the location of
the application's source files. Use this dialog box to locate the source. The filename you
specify in the dialog box must match the filename specified in the debug symbols
(located on the Web server).

Visual Studio
Stepping Into an XML Web Service

In Visual Studio .NET, you can step into an XML Web service as though you were stepping into
an ordinary function call. Stepping into an XML Web service is possible when both the client
and the service are written in managed code (Visual Basic, C#, or Managed Extensions for C++).
Stepping occurs automatically across threads, processes, and even machines.

When you step into an XML Web service call, the debugger automatically attaches to the
ASP.NET worker process (aspnet_wp.exe for IIS5.0 and IIS 5.1 on Windows 2000 and
Windows XP or w3wp.exe on IIS6 on Windows Server 2003). The ASP.NET worker process
can be on the local machine or on a remote machine.

Note To attach to ASP.NET worker process, you must be an Administrator on the server where
the process is running. On the client machine, you be in the Debugger Users group or an
Administrator. (See Adding Debugger Users.) If the XML Web service is running on the client,
you must be an Administrator on the client.
If the ASP.NET worker process is running on an RTM machine, the ASP.NET worker process
must run under a user that is a member of Debugger Users on that machine.
If you want to debug both managed and unmanaged code, both types of debugging must be
enabled in your project. You can enable unmanaged debugging by choosing the Enable
Unmanaged Debugging option in the <Project> Properties dialog box (in the Configuration
Properties folder, Debugging category).

When the execution breaks in the XML Web service, you can view a merged callstack that
contains calls from both the client and the XML Web service. To see all the information, you
may need to enable the display of calls between threads.

To display calls between threads

1. Right-click the Call Stack window.


2. From the shortcut menu, choose Include Calls To/From Other Threads.

Once you have stepped into the XML Web service, you can use all the ordinary execution
commands such as Step and Continue. At the end of the XML Web service call, you can step
out and back into the client that called the XML Web service. When you step out of an XML
Web service, the debugger remains attached to the ASP.NET worker process. The debugger
detaches from the ASP.NET worker process when you end the debugging session (by choosing
Stop Debugging from the Debug menu, for example). You can manually detach the ASP.NET
worker process using the Processes dialog box. (For details, see Detaching Programs.)

Visual Studio
ASP.NET Debugging: System Requirements

This topic describes the operating system requirements for debugging ASP.NET Web
applications with Visual Studio .NET.

Local debugging is the scenario in which you are trying to debug a Web application on your
local (client) machine. In other words, Visual Studio .NET and the Web application are installed
and running on the same machine. Local debugging of ASP.NET applications requires Windows
2000 Professional, Windows 2000 Server, Windows 2000 Advanced Server, Windows XP
Professional, and Windows Server 2003.

Remote debugging is the scenario in which you run Visual Studio .NET on one machine (the
client) and debug a Web application running on another machine (the server). Remote debugging
of ASP.NET applications requires a local client Windows 2000 or Windows XP (any edition).
The remote server must be running Windows 2000 Professional, Windows 2000 Server,
Windows 2000 Advanced Server, Windows XP Professional, or Windows Server 2003.

For all supported operating systems:

• To debug an ASP.NET application, you must be an administrator on the


machine that the ASP.NET Web server is running or your name must be in the
Debugger Users group if the ASP.NET worker process is running under your
user account.
• For remote debugging, local and remote machines must be on a domain
setup or, if they are on a workgroup setup, both machines must be running
Windows 2000 or Windows XP.
• To debug the ASP.NET worker process (aspnet_wp.exe or w3wp.exe), you
must have permission to debug that process. If the worker process is running
as ASPNET (the default), you need Administrator privileges to debug it. For
remote debugging, you need Administrator privileges on the remote server
machine. On Windows 2000 and Windows XP, you can debug aspnet_wp.exe
without Administrator privileges if you edit the machine.config file for the
aspnet_wp.exe process so that aspnet_wp.exe runs under your user account
rather than ASPNET. On Windows Server 2003, you can use IIS to change the
account w3wp.exe runs under.

To run aspnet_wp.exe runs under a user account

1. Open the machine.config file, located on your machine in the CONFIG folder
under the path where you installed the runtime.
2. Find the <processModel> section and change the user and password attributes
to the name and password of the user account you want aspnet_wp.exe to
run under.
3. Save the machine.config file.
4. Find the Temporary ASP.NET Files folder, which should be in the same path as
the CONFIG folder. Right-click the Temporary ASP.NET Files folder and choose
Properties from the shortcut menu.
5. In the Temporary ASP.NET Files Properties dialog box, choose the
Security tab.
6. Click the Advanced button.
7. In the Access Control Settings for Temporary ASP.Net Files dialog box,
click the Add button.
8. Enter the user name in the Name box, and then click OK.
9. In the Permission Entry for Temporary ASP.NET Files dialog box, give
the user full permissions, and then click OK to close the Temporary
ASP.NET Files Properties dialog box.

Windows 2000

You can use Visual Studio .NET on a Windows 2000 client machine to debug ASP.NET
applications running locally or on a remote server. The debugging client may be running
Windows 2000 Workstation or Workstation Server (with or without Terminal Services). If the
client machine is running Windows 2000 Workstation, you must install Microsoft Internet
Information Services before debugging.

You can begin ASP.NET debugging by launching an application within a Visual Studio (by
choosing a Start or Step command from the Debug menu) or by launching the application
without debugging and using the Processes dialog box to attach to it. For more information, see
Attaching to a Running Program or Multiple Programs.

Windows XP and Windows Server 2003

From a client machine running Windows XP Professional or Windows Server 2003, you can
debug ASP.NET applications running locally or on a remote server. From a client machine
running Windows XP Home Edition, you cannot debug ASP.NET applications.

You can begin ASP.NET debugging by launching an application within a Visual Studio (by
choosing a Start or Step command from the Debug menu) or by launching the application
without debugging and using the Processes dialog box to attach to it. For more information, see
Attaching to a Running Program or Multiple Programs.

Visual Studio

Debugging ASP.NET Web Applications

Debugging an ASP.NET Web application with Visual Studio .NET is similar to debugging a
Windows Form or any other Windows application. The fact that application is running on the
Web should be mostly transparent to you.

In This Section
Debugging ASP.NET Applications During Development
Provides steps for debugging an ASP.NET application during development.
These steps include setting debug mode for the configuration file, setting
project properties, starting the debugger, setting and clearing breakpoints,
stepping, and ending the debugging session.

Debugging Deployed ASP.NET Applications

Discusses debugging a Web application that is already deployed and running


on a server. Information includes considerations and steps for debugging.

Debugging Web Applications on a Remote Server

Lists prerequisites for debugging a Web application on a remote server.

Debugging Client-Side Scripts

Discusses testing scripts and client side scripts in ASP.NET pages. Tasks you
can perform when debugging client-side scripts in a Web page include
viewing source code, controlling the pace of script execution with breakpoints
and stepping, viewing and changing variable and property values, and
viewing and controlling script flow with the Call Stack window.

Debugging ASP.NET Web Services

Describes debugging ASP.NET Web services. Information includes debugging


an XML Web service on //localhost, debugging an XML Web service on a
remote server, and debugging a deployed XML Web service.

ASP.NET Debugging: System Requirements

Describes the operating system requirements for debugging ASP.NET Web


applications with Visual Studio .NET.

Debug Mode in ASP.NET Applications

Discusses setting debug mode for an ASP.NET application. Information


includes a description of Web.config files, suggestions for editing the file,
sample code, and the behavior of hierarchical configuration files.
Global Exception Handling with ASP.NET
Global Exception Handling

You can't debug a problem if you don't know that it exists. After you take your web application
live, you are no longer the only one who is using it (hopefully), so you need an effective plan to
track exceptions when they occur while others are surfing your site. A great way to do this is to
implement an exception handler at the application level. This will allow you to consolidate the
logging and notification parts of your exception handling in one convenient place. As you'll see
from the code examples that follow, your global exception handler can handle both specific
exceptions that you trap in your code and generic unhandled exceptions.

• Post a comment
• Email Article
• Print Article
• Share Articles
o Digg
o del.icio.us
o Slashdot
o DZone
o Reddit
o StumbleUpon
o Facebook
o FriendFeed
o Furl
o Newsvine
o Google
o LinkedIn
o MySpace
o Technorati
o Twitter
o Windows Live
o YahooBuzz

After your global exception handler has done its work, you'll want to redirect the users of
your website to a friendly page that tells them that something has gone wrong, and then provide
them with customer support information as well as a link back to your web application's home
page.
Implementing the Application_Error Event Handler

The HttpApplication class in the System.Web namespace implements an Error event handler.
This should not be confused with the HttpApplicationState class, which contains the
definition for the Application object that you use in a typical ASP.NET page. You can
implement this event handler in the global.asax file as shown in Listings 1 and 2.

Listing 1: Application_Error Event Handler


<%@ Application Language="C#" %>
<%@ Import Namespace="System.Diagnostics" %>

<script language="C#" runat="server">


void Application_Error(object sender, EventArgs e)
{
//get reference to the source of the exception chain
Exception ex = Server.GetLastError().GetBaseException();

//log the details of the exception and page state to the


//Windows 2000 Event Log
EventLog.WriteEntry("Test Web",
"MESSAGE: " + ex.Message +
"\nSOURCE: " + ex.Source +
"\nFORM: " + Request.Form.ToString() +
"\nQUERYSTRING: " + Request.QueryString.ToString() +
"\nTARGETSITE: " + ex.TargetSite +
"\nSTACKTRACE: " + ex.StackTrace,
EventLogEntryType.Error);

//Insert optional email notification here...


}
</script>

Listing 2: Application_Error Event Handler (VB)


<%@ Application Language="VB" %>
<%@ Import Namespace="System.Diagnostics" %>

<script language="VB" runat="server">


Sub Application_Error(sender As Object, e As EventArgs)
'get reference to the source of the exception chain
Dim ex As Exception = Server.GetLastError().GetBaseException()

'log the details of the exception and page state to the


'Windows 2000 Event Log
EventLog.WriteEntry("Test Web", _
"MESSAGE: " & ex.Message & _
"\nSOURCE: " & ex.Source & _
"\nFORM: " & Request.Form.ToString() & _
"\nQUERYSTRING: " & Request.QueryString.ToString() & _
"\nTARGETSITE: " & ex.TargetSite & _
"\nSTACKTRACE: " & ex.StackTrace, _
EventLogEntryType.Error)

'Insert optional email notification here...


End Sub
</script>

First, you have to be sure to set a reference to the System.Diagnostics namespace. You'll use the
EventLog class in this namespace to write exception details to the Windows 2000 event log.
Inside the Application_Error event handler, you declare an Exception object and initialize it
through a call to Server.GetLastError().GetBaseException().

The GetLastError() method of the Server object simply returns a reference to a generic
HttpException. This is a wrapper that was placed around the original exception when it was
passed from your ASP.NET page to the Application_Error event. To get access to the original
exception, you need to call its GetBaseException() method. This will yield the original
exception information, regardless of how many layers have been added to the exception tree.

Next, you make a call to the WriteEntry() method of the EventLog class. There are several
overloaded signatures for this method. The implementation that we chose to use here accepts
three parameters. The first parameter is the source of the error. It appears in the Source field of
the Windows 2000 event log viewer. The second parameter is the log data itself. You can see
that we have added a lot of information to help track down what caused the exception, including
the exception message, the exception source, the contents of the Form collection, the contents of
the QueryString collection, the name of the method that generated the error (TargetSite), and
a complete stack trace.

Note that the stack trace contains the name of the file that was the source of the exception.
However, it strips off the contents of the query string—hence the need to specifically include it
previously. The third and final parameter to the WriteEntry() method is an enumeration of type
EventLogEntryType. We chose to use the Error element of the enumeration.

At the end of the event handler, we inserted a comment block where you can optionally put code
to email the exception information to your IT support staff. Discussion of the different
messaging paradigms in the .NET framework is beyond the scope of this article.

After the Application_Error event has completed its work, it automatically redirects the user
of your web application to your custom error page. Optionally, however, you can use the
Server.ClearError() method after you have logged the exception and redirect your user using
the Server.Execute() method, specifying the page that you want to load in the user's browser.

The code that you have just implemented will capture all unhandled exceptions that occur in
your web application. If you need to do some cleanup in the event of an exception and you
implement structured exception handling inside your ASP.NET page, you can still leverage the
global exception handler. Listings 3 and 4 present examples of how you would do it.

Listing 3: Throwing a Handled Exception


<%@ Page Language="C#" %>

<script language="C#" runat="server">


protected void button1_click(object sender, EventArgs e)
{
try
{
//do some complex stuff

//generate your fictional exception


int x = 1;
int y = 0;
int z = x / y;
}
catch(DivideByZeroException ex)
{
//put cleanup code here
throw(ex);
}
}
</script>

<form runat="server">
<asp:button id="button1" onclick="button1_click"
text="click me" runat="server" />
</form>

Listing 4: Throwing a Handled Exception (VB)


<%@ Page Language="VB" %>

<script language="VB" runat="server">


Protected Sub button1_click(sender As Object, e As EventArgs)
Try
'do some complex stuff

'generate your fictional exception


Dim x As Integer = 1
Dim y As Integer = 0
Dim z As Integer = x / y
Catch ex As DivideByZeroException
'put cleanup code here
Throw(ex)
End Try
End Sub
</script>

<form runat="server">
<asp:button id="button1" onclick="button1_click"
text="click me" runat="server" />
</form>

The code in these listings defines a web form with a text box and a button. When you click the
button, it fires the button1_click event handler. In the event handler, you would do processing
as usual. For the purposes of this demonstration, however, you intentionally generate a
DivideByZeroException. This takes you to the catch block. Here, you can perform any page-
specific cleanup code before calling throw(ex) to pass your exception to the global exception
handler to be logged to the Windows 2000 event log.
When the global exception handler is finished logging the error, the defaultredirect attribute
that you set in your config.web file (discussed in the next section) takes over, and you are
redirected to the error.aspx page to display your friendly message to the user of your web
application.

Setting Up the Custom Error Page

The first step in setting up a custom error page is to modify your config.web file to route the
users of your web application to a friendly error page if an exception occurs. It helps to boost
users' confidence in your site when it can recover gracefully from the unexpected. Add the code
in Listing 5 to the config.web file of your web application.

Listing 5: Adding the <customerrors> Tag to Your Config.web


File
<configuration>
<customerrors mode="On" defaultredirect="error.aspx" />
</configuration>

Note that your config.web file might already have a <customerrors> tag, so you might only
need to modify the existing one. The mode attribute of the <customerrors> tag has three
settings: On, Off, and RemoteOnly. If the mode is On, users will always be redirected to the
custom error page specified by the defaultredirect attribute if an unhandled exception occurs.
If the mode is Off, the details of any exception that occurs will be shown to the user in the
browser. The RemoteOnly mode is a hybrid of the two other modes. If you are browsing your
web application while sitting at the web server itself, it behaves like the Off mode. All other
browsers of the site will get the behavior of the On mode. If no defaultredirect attribute is set,
a default ASP.NET "friendly, yet not so friendly" message will be displayed to the user when
exceptions occur.

Next, you need to build the custom error page (error.aspx) referenced in the config.web file. This
is just an ordinary ASP.NET page that includes helpful information for the user of your web
application if an error occurs. An extremely simple example is the one in Listing 6.

Listing 6: Simple Custom Error Page


<html>
<head>
<title>My web application: Error page</title>
</head>
<body>
An unexpected error occurred in the application. Please contact [ccc]
customer service at (800)555-5555. Or, you can click [ccc]
<a href="home.aspx">here</a> to go back to the homepage. [ccc]
Thank you for your patience.
</body>
</html>
Exception handling in C# and ASP .Net

Exception handling is an in built mechanism in .NET framework to detect and handle run time errors.
Exceptions are defined as anomalies that occur during the execution of a program. The .NET framework
provides a rich set of standard exceptions that are used during exceptions handling. Exception handling is
one of the major feature provide by .NET. There might be various reason to handle exception, this can be
caused due to improper user inputs, improper design logic or system errors. In this scenario if application
do not provide a mechanism to handle these anomalies then there might be cases the application may
crash. .NET run time environment provide a default mechanism, which terminates the program
execution.

This article provides insight about exception handling on the basis of ASP.NET and C# as code behind.

ASP.NET Exception Handling

In ASP.NET exception handling is achieved using the Try ? Catch ? Finally block. All the three are
ASP.NET keywords and are used do exception handling. The try block encloses the statements that
might throw an exception whereas catch block handles any exception if one exists. The finally block can
be used for doing any clean up process. Any general ASP.NET exception forces the application to
terminate without allowing the code to continue executing, resulting in an error page.

try
{
// Statements that are can cause exception
}
catch(Type x)
{
// Statements to handle exception
}
finally
{
// Statement to clean up
}

try-catch-finally block in ASP.NET

<Script runat=server>
Public Page_Load(sender As Object, e As EventArgs)
{
try
{
// Statements that are can cause exception
}
catch(Type x)
{
// Statements to handle exception
}
finally
{
// Statement to clean up
}
}
</Script>

When an error occurs, we get an instance of exception or possibly a derived, more specialized
instanced, such as a NoNullAllowedException when attempting to insert a null value into a SQL table row
that does not allow null value.

Exceptions provide us with detailed information about what occurred; for example stack trace, inner
exception details, message, and additional details.

Unhandled Exceptions:

When some of exceptions are not handled in Try ? Catch ? Finally block of ASP.NET still there are ways
provided by the framework facilities for handling the exception through two events:

Page_Error
Application_Error

Page and Application Error Event Handlers

This is very useful in cases where an exception is unexpected and does not occur within the bounds of
a Try/Catch/Finally block. These exceptions are usually an indicator that something is substantially wrong
with the application. That is, some abnormal exception has occurred and no means are provided to
handle exception. In this case there is the option to deal with the error at either the Page or Application
level.

If the exception is dealt at Page level, the details needs to be provided for the Page_Error event:

C# way of implementation is as follows

public void Page_Error(Object sender, EventArgs e) {


// Implementation here
}

This event is implemented within the Page that the error may occur within.
Alternatively, the Application_Error event can be used to handled the above scenario. Unlike the
Page_Error event, the Application_Error event is implemented in global.asax and any unhandled
exception that occurs within our application raises from this event.

C# way of implementation is as follows

public void Application_Error(Object sender, EventArgs e) {


// Implementation here
}

Working with Custom Errors

The default settings that is available in machine.config is as follows

<customErrors mode="RemoteOnly"/>

The mode attribute has three options that can be used for customizing the error:

RemoteOnly:

When an unhandled exception occurs, localhost that is where the web pages are placed will see the
ASP.NET error page, which includes compilation details and accessibility to the full source. However,
remote users ie. the client browser are shown a different ASP.NET error page that simply lets them know
an error occurred. No other details are provided. If any custom error page is available then, this page will
be displayed to the remote user when any exception occurs.

On:

The detailed ASP.NET error page is never shown, even to local users. If a custom error page is available,
it is displayed.

Off:

The detailed ASP.NET error page is always displayed, even if a custom error page exists.

In addition to the mode settings, there are several other configuration options for the customErrors
section of the configuration.

defaultRedirect:

A custom error page that client is redirected to when an error occurs. For example, if a error page
designed with name errorPage.aspx, then the following configuration entry in web.config for an ASP.NET
application has to made for obtaining the desired results :

<customErrors mode="On" defaultRedirect=" errorPage.aspx"/>


Whenever an unhandled exception occurs within our application, the user is redirected to
errorPage.aspx, which provides a user-friendly error message.

Special Case:

This option provides a special case for the custom error page depending upon the HTTP status code. For
example, a custom error page if the request attempts to access a page does not exist (HTTP 404).
Following configuration element need to be put that can be nested in <customErrors>, <error> as

<customErrors mode="On" defaultRedirect=" errorPage.aspx">


<error statusCode="404" redirect=" errorPage404.aspx"/>
</customErrors>

Now, whenever a request is made for a document that cannot be located, we can send the request to a
custom page..

C# Exception Handling

In C# exception handling is achieved using the try ? catch ? finally block. All the three are C# keywords
that are used do exception handling. The try block encloses the statements that might throw an exception
whereas catch block handles any exception if one exists. The finally block can be used for doing any
clean up process.

try
{
// Statements that are can cause exception
}
catch(Type x)
{
// Statements to handle exception
}
finally
{
// Statement to clean up
}

try-catch-finally block in C#:

As mentioned earlier any exception that occurs inside the try block, transfers control to the appropriate
catch block and later to the finally block. In C#, both catch and finally blocks are optional. The try block
can exist either with one or more catch blocks or a finally block or with both catch and finally blocks.

In cases when there is no exception inside the try block, the control directly transfers to finally block. So
the statements inside the finally block are always executed. C#, exceptions are objects of the type
Exception. The Exception base class is used for any exceptions in C#. Some of the standard exceptions
derived of Exception class are DivideByZeroExcpetion, ArgumentException etc.

Example of un-handled exception:


The following program will encounter an exception when executed. At the time of compilation there will be
no error caused. In the following code division by zero exception occurs. The division by zero is a runtime
anomaly and program terminates with an error message.

//C#: Exception Un - Handled

using System;
class UnHandledException
{
public static void Main()
{
int x = 0;
int intTemp = 100/x;
Console.WriteLine(intTemp);
}
}

Any un-handled exceptions finds the appropriate block where it is handled, if they are no appropriate
blocks then the default .NET runtime will terminate the execution of the entire program.

Example of handled exception:

The above program can be modified in the following manner to track the exception. You can see the
usage of standard DivideByZeroException class

//C#: Exception Handling

using System;
class HandledException
{
public static void Main()
{
int x = 0;
int intTemp = 0;
try
{
intTemp = 100/x;
Console.WriteLine(?Program terminated before this statement?);
}
catch(DivideByZeroException de)
{
Console.WriteLine("Division by Zero occurs");
}
finally
{

Console.WriteLine("Result is {0}", intTemp);


}
}
}

In the above example the program ends in an expected way instead of program termination. At the time
of exception program control passes from exception point inside the try block and enters catch blocks. As
the finally block is present, so the statements inside final block are executed.

Example of exception un handled in catch block

As in C#, the catch block is optional. The following program is perfectly legal in C#.

//C#: Exception Handling without catch block

using System;
class HandledException
{
public static void Main()
{
int x = 0;
int intTemp = 0;
try
{
intTemp = 100/x;
Console.WriteLine("Not executed line");
}
finally
{
Console.WriteLine("Inside Finally Block");
}
Console.WriteLine("Result is {0}", intTemp);
}
}

The above example will produce no exception at the compilation time but the program will terminate due
to un handled exception. But the thing that is of great interest to all the is that before the termination of the
program the final block is executed.

Example of Multiple Catch Blocks:

A try block can throw multiple exceptions, that can handle by using multiple catch blocks. Important point
here is that more specialized catch block should come before a generalized one. Otherwise the compiler
will show a compilation error.

//C#: Exception Handling: Multiple catch

using System;
class HandledException
{
public static void Main()
{
int x = 0;
int intTemp = 0;
try
{
intTemp = 100/x;
Console.WriteLine("Not executed line");
}
catch(DivideByZeroException de)
{
Console.WriteLine("DivideByZeroException" );
}
catch(Exception ee)
{
Console.WriteLine("Exception" );
}
finally
{
Console.WriteLine("Finally Block");
}
Console.WriteLine("Result is {0}", intTemp);
}
}

Example of Catching all Exceptions

By providing a catch block without a brackets or arguments, we can catch all exceptions occurred inside
a try block. Even we can use a catch block with an Exception type parameter to catch all exceptions
happened inside the try block since in C#, all exceptions are directly or indirectly inherited from the
Exception class.

//C#: Exception Handling: Handling all exceptions

using System;
class HandledException
{
public static void Main()
{
int x = 0;
int intTemp = 0;
try
{
intTemp = 100/x;
Console.WriteLine("Not executed line");
}
catch
{
Console.WriteLine("oException" );
}
Console.WriteLine("Result is {0}", intTemp);
}
}

The following program handles all exception with Exception object.

//C#: Exception Handling: Handling all exceptions

using System;
class HandledException
{
public static void Main()
{
int x = 0;
int intTemp = 0;
try
{
intTemp = 100/x;
Console.WriteLine("Not executed line");
}
catch(Exception e)
{
Console.WriteLine("oException" );
}
Console.WriteLine("Result is {0}", intTemp);
}
}

Example of Throwing an Exception:

C# provides facility to throw an exception programmatically. The 'throw' keyword is used for doing the
same. The general form of throwing an exception is as follows.

throw exception_obj;

For example the following statement throw an ArgumentException explicitly.

throw new ArgumentException("Exception");

//C#: Exception Handling:

using System;
class HandledException
{
public static void Main()
{
try
{
throw new DivideByZeroException("Invalid Division");
}
catch(DivideByZeroException e)
{
Console.WriteLine("Exception" );
}
Console.WriteLine("Final Statement that is executed");
}
}

Standard Exceptions

Exception are categorised into two types

a) exceptions generated by an executing program


b) exceptions generated by the common language runtime.

As explained earlier section System.Exception is the base class for all exceptions in C#. Several
exception classes inherit from base class including ApplicationException and SystemException. These
two classes form the basis for most of the runtime exceptions. Other exceptions are derived directly from
System.Exception include IOException, WebException etc.

The common language runtime throws SystemException. The ApplicationException is thrown by a user
program rather than the runtime. The SystemException includes the ExecutionEngineException,
StaclOverFlowException etc. It is generally not recommended to catch SystemExceptions also it is not
good programming practice to throw SystemExceptions in applications. Following are few of the example
of the above stated exception.

System.OutOfMemoryException
System.NullReferenceException
Syste.InvalidCastException
Syste.ArrayTypeMismatchException
System.IndexOutOfRangeException
System.ArithmeticException
System.DevideByZeroException
System.OverFlowException

User-defined Exceptions:

C#, allows to create user defined exception class this class should be derived from Exception base class.
So the user-defined exception classes must inherit from either Exception class or one of its standard
derived classes.

//C#: Exception Handling: User defined exceptions


using System;
class UserDefinedException : Exception
{
public MyException(string str)
{
Console.WriteLine("User defined exception");
}
}
class HandledException
{
public static void Main()
{
try
{
throw new UserDefinedException ("New User Defined Exception");
}
catch(Exception e)
{
Console.WriteLine("Exception caught here" + e.ToString());
}
Console.WriteLine("Final Statement that is executed ");
}
}

.NET Framework Developer's Guide


Best Practices for Handling Exceptions

A well-designed set of error handling code blocks can make a program more robust and less
prone to crashing because the application handles such errors. The following list contains
suggestions on best practices for handling exceptions:

• Know when to set up a try/catch block. For example, you can programmatically check for
a condition that is likely to occur without using exception handling. In other situations,
using exception handling to catch an error condition is appropriate.

The following example uses an if statement to check whether a connection is closed. You
can use this method instead of throwing an exception if the connection is not closed.

[Visual Basic]

If conn.State <> ConnectionState.Closed Then


conn.Close()
End If
[C#]
if(conn.State != ConnectionState.Closed)
conn.Close();

In the following example, an exception is thrown if the connection is not closed.

[Visual Basic]

Try
conn.Close()
Catch ex As InvalidOperationException
'Do something with the error or ignore it.
End Try
[C#]
try {
conn.Close();
}
catch(InvalidOperationException ex) {
//Do something with the error or ignore it.
}

The method you choose depends on how often you expect the event to occur. If the event
is truly exceptional and is an error (such as an unexpected end-of-file), using exception
handling is better because less code is executed in the normal case. If the event happens
routinely, using the programmatic method to check for errors is better. In this case, if an
exception occurs, the exception will take longer to handle.

• Use try/finally blocks around code that can potentially generate an exception and
centralize your catch statements in one location. In this way, the try statement generates
the exception, the finally statement closes or deallocates resources, and the catch
statement handles the exception from a central location.
• Always order exceptions in catch blocks from the most specific to the least specific. This
technique handles the specific exception before it is passed to a more general catch block.
• End exception class names with the word "Exception". For example:

[Visual Basic]

Public Class EmployeeListNotFoundException


Inherits Exception
[C#]
public class MyFileNotFoundException : ApplicationException {
}

• When creating user-defined exceptions, you must ensure that the metadata for the
exceptions is available to code executing remotely, including when exceptions occur
across application domains. For example, suppose Application Domain A creates
Application Domain B, which executes code that throws an exception. For Application
Domain A to properly catch and handle the exception, it must be able to find the
assembly containing the exception thrown by Application Domain B. If Application
Domain B throws an exception that is contained in an assembly under its application
base, but not under Application Domain A's application base, Application Domain A will
not be able to find the exception and the common language runtime will throw a
FileNotFoundException. To avoid this situation, you can deploy the assembly containing
the exception information in two ways:
• Put the assembly into a common application base shared by both application
domains

- or -

• If the domains do not share a common application base, sign the assembly
containing the exception information with a strong name and deploy the assembly
into the global assembly cache.
• In C# and the Managed Extensions for C++, use at least the three common constructors
when creating your own exception classes. For an example, see Using User-Defined
Exceptions.
• In most cases, use the predefined exceptions types. Define new exception types only for
programmatic scenarios. Introduce a new exception class to enable a programmer to take
a different action in code based on the exception class.
• Do not derive user-defined exceptions from the Exception base class. For most
applications, derive custom exceptions from the ApplicationException class.
• Include a localized description string in every exception. When the user sees an error
message, it is derived from the description string of the exception that was thrown, rather
than from the exception class.
• Use grammatically correct error messages, including ending punctuation. Each sentence
in a description string of an exception should end in a period.
• Provide Exception properties for programmatic access. Include extra information in an
exception (in addition to the description string) only when there is a programmatic
scenario where the additional information is useful.
• Return null for extremely common error cases. For example, File.Open returns null if the
file is not found, but throws an exception if the file is locked.
• Design classes so that an exception is never thrown in normal use. For example, a
FileStream class exposes another way of determining whether the end of the file has
been reached. This avoids the exception that is thrown if you read past the end of the file.
The following example shows how to read to the end of the file.

[Visual Basic]

Class FileRead
Sub Open()
Dim stream As FileStream = File.Open("myfile.txt", FileMode.Open)
Dim b As Byte

' ReadByte returns -1 at EOF.


While b = stream.ReadByte() <> True
' Do something.
End While
End Sub
End Class
[C#]
class FileRead {
void Open() {
FileStream stream = File.Open("myfile.txt", FileMode.Open);
byte b;

// ReadByte returns -1 at EOF.


while ((b == stream.ReadByte()) != true) {
// Do something.
}
}
}

• Throw an InvalidOperationException if a property set or method call is not appropriate


given the object's current state.
• Throw an ArgumentException or a class derived from ArgumentException if invalid
parameters are passed.
• The stack trace begins at the statement where the exception is thrown and ends at the
catch statement that catches the exception. Be aware of this fact when deciding where to
place a throw statement.
• Use exception builder methods. It is common for a class to throw the same exception
from different places in its implementation. To avoid excessive code, use helper methods
that create the exception and return it. For example:

[Visual Basic]

Class File
Private fileName As String

Public Function Read(bytes As Integer) As Byte()


If Not ReadFile(handle, bytes) Then
Throw NewFileIOException()
End If
End Function 'Read

Function NewFileIOException() As FileException


Dim description As String = __unknown ' Build localized string,
including fileName.
Return New FileException(description) '
End Function 'NewFileIOException
End Class 'File
[C#]
class File {
string fileName;
public byte[] Read(int bytes) {
if (!ReadFile(handle, bytes))
throw NewFileIOException();
}
FileException NewFileIOException() {
string description = // Build localized string, including
fileName.
return new FileException(description);
}
}
Alternatively, use the exception's constructor to build the exception. This is more
appropriate for global exception classes, such as ArgumentException.

• Throw exceptions instead of returning an error code or HRESULT.


• Clean up intermediate results when throwing an exception. Callers should be able assume
that there are no side effects when an exception is thrown from a method.

Exception-handling in ASP.NET

Introduction
Like in other .NET-applications, exception-handling is also available in ASP.NET-
applications. There are a few extensions and special features for exception-handling
in ASP.NET that will be explained in this article: Predefined error-handlers, custom
error-pages and IHttpModules.

Normal exception-handling

Of course your can use the known try/catch/finally-cascade of exception handling in


your code:

try
{
File.OpenRead( path );
}
catch( System.IO.FileNotFoundException ex )
{
// handle error
}
finally
{
// cleanup
}

But in ASP.NET-applications you have got some extended kinds of error-handling-


techniques at hand:

Error handlers
You can use predined error-handlers in your aspx-Page or in Global.asax-file. Here
you can catch errors that occur in special scopes of your web-application. To get the
Exception that occurred, you can use the method GetLastError() of the Server-
property.

// Define it in your aspx-page


private void Page_Error(object sender, System.EventArgs e)
{
Exception ex = Server.GetLastError();
}

// Define it in Global.asax
protected void Application_Error(Object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
}

This is very useful, cause in a lot of cases, your don't want to implement exception-
handling for every block in your code where it could occur. An often used scenario is
catching your exeption in Application_Error and redirect to a special page, to offer a
user-friendly error-page. Therefore you can use the technique above and redirect
manually via code, or you can use the ASP.NET-feature explained in the next
paragraph.

Custom Error Pages

The redirection to a custom error-page can be coded but it is more handy to do it by


configuration. Here is how you can configure it in your web.config:

<customErrors mode="On" defaultRedirect="Error.htm"/>

If an unhandled exception occurs, the user will be redirected to Error.htm, a page


that you can define and design as you like. But you can use more detailled
configuration for this. On known errors you can navigate to special error pages. An
example for this is, when a page the user navigates to does not exist. Then the
error 404 occurs and this is how you can tell ASP.NET to go to a special error-page
for that:
<customErrors mode="On" defaultRedirect="Error.htm">
<error statusCode="404" redirect="MyErrorPage404.aspx" />
</customErrors>

Nice feature, isn't it? If you don't want to declare your error-page globally, you can
also define it in the Page-directive of your aspx-file:

<%@ Page language="c#" Codebehind="Errors.aspx.cs"


AutoEventWireup="false"
Inherits="TestExceptions.Errors"
errorPage="MyErrPage.aspx" %>

Now the user is redirected to the page defined here, but only if an error in this
special page occurs.

Error-handling in IHttpModule

Another possiblity to handle errors is in an own IHttpModule. To define it, you have
to implement the interface IHttpModule and bind your error-handler in this class:

public class MyErrorModule : IHttpModule


{
public MyErrorModule()
{
}

#region IHttpModule Members

public void Dispose()


{
}

public void Init(HttpApplication context)


{
context.Error += new EventHandler(context_Error);
}

void context_Error(object sender, EventArgs e)


{
Exception e = HttpContext.Current.Server.GetLastError();

// handle exception

// Clear the error so that it doesn't occur again in


// the Application_Error-handler
HttpContext.Current.Server.ClearError();
HttpContext.Current.Response.Redirect("ErrorPage.htm");
}

#endregion
}

You also need to configure this HttpModule in your web.config-File:

<httpModules>
<add type="MyErrorModule, MyWebApp" name="MyErrorModule "/>
</httpModules>

So what is the benefit of using an own HttpModule. Well, the name already says it:
You have a modularization for your error-handling. You can change your
implementation at one place without touching your application-logic and you can
change the errorhandling of your appliation by defining another HttpModule and
configuring it in your web.app.

Custom Error Handling in ASP.NET

Introduction

Structured exception handling is a fundamental part of the CLR and provides .Net
programmers a great way of managing errors. In addition to CLR exception system,
ASP.Net also provides ways of handling errors.

When a runtime or design-time error occurs in an application, ASP.Net shows a default error
page that gives a brief description of the error along with the line number on which the
error occurred. A developer would wish to view this default error page, during the testing
of the application since the description helps him in rectifying the error. But he would never
want a user trying to access his application, to view this error page. The user would be least
bothered to know about the error. Instead of showing the default error page, it would be
more sensible to show a customized error page that would let the user send notification of
the error to the administrator.

Explanation

Consider an example of an ASP.Net application that generates an error intentionally to show


how ASP.Net detects it and shows the default error page. The below given webform contains
a label and a button server control. In the eventhandler for the button click event, the user
will be redirected to another webform "Trial.aspx". Since the page being redirected to, is
missing ASP.Net will show the default error page indicating it is a runtime error.

Unlike classic ASP, ASP.Net separates the code for the business logic from the content (i.e
HTML and interface logic). The sample application has two files named "webform1.aspx"
containing the content and "webform1.aspx.vb" containing the code.
WebForm1.aspx

<%@ Page Language="vb" AutoEventWireup="false"


Codebehind="WebForm1.aspx.vb" Inherits="ErrorSample.WebForm1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<title></title>
<meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0">
<meta name="CODE_LANGUAGE" content="Visual Basic 7.0">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema" content=
"http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<asp:Label id="Message" style="Z-INDEX: 101; LEFT: 34px;
POSITION: absolute; TOP: 46px" runat="server"></asp:Label>
<asp:Button id="ErrorButton" style="Z-INDEX: 102; LEFT: 268px;
POSITION: absolute; TOP: 41px" runat="server" Text="Generate
Error"></asp:Button>
</form>
</body>
</HTML>

WebForm1.aspx.vb

Public Class WebForm1


Inherits System.Web.UI.Page
Protected WithEvents Message As System.Web.UI.WebControls.Label
Protected WithEvents ErrorButton As System.Web.UI.WebControls.Button
Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Handles MyBase.Load
Message.Text = "This sample page generates an Error..."
End Sub
Public Sub ErrorButton_Click(ByVal sender As Object, ByVal e As
System.EventArgs)
Handles ErrorButton.Click
Response.Redirect("Trial.aspx")
End Sub
End Class

Now if you try to run the above web form by viewing it on the browser, you will get the
below shown web page:
Now if you click on the button labeled "Generate Error", you will get the below shown
default ASP.Net error page.

Customizing Error Page

To customize the default error page, one will have to change the default configuration
settings of the application.
There are three error modes in which an ASP.Net application can work:

1. Off Mode
2. On Mode
3. RemoteOnly Mode

The Error mode attribute determines whether or not an ASP.Net error message is displayed.
By default, the mode value is set to "RemoteOnly".

• Off Mode
When the error attribute is set to "Off", ASP.Net uses its default error page for both
local and remote users in case of an error.
• On Mode
In case of "On" Mode, ASP.Net uses user-defined custom error page instead of its
default error page for both local and remote users. If a custom error page is not
specified, ASP.Net shows the error page describing how to enable remote viewing of
errors.
• RemoteOnly
ASP.Net error page is shown only to local users. Remote requests will first check the
configuration settings for the custom error page or finally show an IIS error.

Configuration File

Customization of error page can be implemented by adding a value for an attribute


"defaultRedirect" in the <customErrors> tag of the configuration file "web.config". This file
determines configuration settings for the underlying application.

• Off Mode
In this scenario, set the mode attribute value to "Off" as shown below:

Web.Config File

<?xml version="1.0" encoding="utf-8" ?>


<configuration>
<system.web>
<customErrors mode="Off" />
</system.web>
</configuration>

When the sample ASP.Net web page is viewed in the browser from the remote
machine, one gets the below shown default error page.
The above example thus shows that, whether it is local or remote access, ASP.Net
error page is shown.

On Mode

In this scenario, set the mode attribute value to "On" as shown below:

Web.Config File
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<customErrors defaultRedirect="error.htm" mode="On" />
</system.web>
</configuration>

As shown in the configuration file, the "defaultRedirect" attribute has been set to a
user-defined page "error.htm". The user-defined error page can be an ASP.Net web
page, classic ASP page or a simple HTML page.

For example, the contents of the user-defined error page "error.htm" can be given as
follows:

Error.htm

<HTML>
<BODY>
<b>
We are very sorry for the inconvenience caused to you...<br>
</b>
</BODY>
</HTML>

When the sample ASP.Net web page is viewed in the browser from the remote/local
machine, one gets the below shown custom error page.

• RemoteOnly Mode

In this scenario, set the mode attribute value to "RemoteOnly" as shown below:

Web.Config File
<?xml version="1.0" encoding="utf-8" ?>
configuration>
<system.web>
<customErrors defaultRedirect="error.htm" mode="RemoteOnly" />
</system.web>
</configuration>

Since the "defaultRedirect" attribute has been set, if the page is requested from a
remote machine page is redirected to "error.htm" and if the page is requested from
the local machine the default error page is shown.
Notification of Error to the Administrator

In a practical web application, customization of error pages is not the only requirement. The
error, if encountered, should be reported to the administrator so that it can be rectified thus
enabling subsequent requests to work properly without any error.

Notification of the error can be sent to the administrator in one of the following two ways:

1. Error can be registered as a log entry in the Windows Event Log on the
administrator's machine.
2. An Email can be sent to the administrator with a suitable error message.

• Writing to the Event Log

In ASP.Net, error can be handled programmatically by writing appropriate code in


the page-level error event, for errors on an individual page or in the application-level
error event for handling errors that may occur in any page of the application.

Therefore, code for writing in the Event Log should be written in either of the events,
depending on the requirement of the application. To illustrate this example, I have
written the code in the application-level event with the error mode set to
"RemoteOnly" and the "defaultRedirect" attribute to "error.htm". The application-
level error event should be included in the global file "global.asax" within the same
application folder.

The contents of the global file can be given as follows:

Writing Log Entry in the Event Log

Imports System.Web
Imports System.Web.SessionState
Imports System.Diagnostics
Public Class Global
Inherits System.Web.HttpApplication
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
Dim ErrorDescription As String = Server.GetLastError.ToString
'Creation of event log if it does not exist
Dim EventLogName As String = "ErrorSample"
If (Not EventLog.SourceExists(EventLogName)) Then
EventLog.CreateEventSource(EventLogName, EventLogName)
End If
' Inserting into event log
Dim Log As New EventLog
Log.Source = EventLogName
Log.WriteEntry(ErrorDescription, EventLogEntryType.Error)
End Sub
End Class

Event Log support is provided in .Net through the namespace "System.Diagnostics".


So, for the above code to work, it is very essential to add a reference to the above-
mentioned namespace in the project. In the event handler for application-level error,
a log named "ErrorSample" is created if it does not exist in the Event Log. If it
already exists, the error entry is added to the existing list of events. After viewing
the page on the browser from a remote machine, the event will get listed in the
Event Log on the administrator's machine as shown below:

Description of the error can be viewed by selecting the appropriate event and double
clicking it. Another form pops up as shown below:
• Sending an Email to the Administrator

To illustrate this example, I have written the code for sending an Email to the
administrator in the application-level error event. The contents of the global file can
be given as follows:

Sending Email To the Administrator

Imports System.Web
Imports System.Web.SessionState
Imports System.Web.Mail
Public Class Global
Inherits System.Web.HttpApplication
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
Dim mail As New MailMessage
Dim ErrorMessage = "The error description is as follows : "
& Server.GetLastError.ToStringmail.To = [email protected]
mail.Subject = "Error in the Site"
mail.Priority = MailPriority.High
mail.BodyFormat = MailFormat.Text
mail.Body = ErrorMessage
SmtpMail.Send(mail)
End Sub
End Class

In the above code, SMTP service is being used to send the mail across. SMTP mail
service support is provided in .Net through the namespace "System.Web.Mail". So,
for the above code to work, it is very essential to add a reference to the above-
mentioned namespace in the project.

Exception Handling Techniques in ASP.NET

Introduction

Exceptions or errors are unusual occurrences that happen within the logic of an application. You
cannot program for every possibility; hence, they are imminent. If an exception occurs within an
application, the user is presented with a yellow page that looks ugly. So, how do you deal with
these situations? You use exception handling techniques in ASP.NET.

Background

There are three ways to handle exceptions/errors in ASP.NET:

1. try-catch block. This is also called Structured Exception Handling (SEH).


2. Error Events.
3. Custom Error Page.

You will look at each one of them in detail in the next sections.
try-catch Block

Enclose code that accesses files, databases, and so forth inside a try-catch block because access
to those resources might be denied due to various reasons causing an exception. The third part of
this block is finally. It is executed irrespective of the fact that an exception has been raised.
Hence, use the finally block to complete the housekeeping jobs.

As a good programming practice, always catch specific exceptions. To view the exception types
supported by the .NET Framework, use the Debug menu and select Exceptions in Visual
Studio.NET.

In the following code, you try to access a table that does not exist in the Northwind database;
therefore, an exception is raised. By using the try catch and finally block, you handle the
exception and display a message.

try
{
con = new SqlConnection("integrated security=SSPI;
data source= (local);persist security info=False;
initial catalog=Northwind");
da = new SqlDataAdapter("Select * from TblNotExisits", con);
ds = new DataSet();
da.Fill(ds);
}
catch(SqlException ex)
{
return "Connection Unsuccessful " + ex.Message;
}
finally
{
con.Dispose();
}
return "Connection Successful";

Using Error Events

There are three different error events in ASP.NET that can be used in conjunction with SEH so
that all exceptions are handled and the user is presented with a user-friendly error message.

1. Page_Error: Occurs when an error occurs within the Web page. This event is in the Web
form.
2. Global_Error: Occurs when an error occurs within the application. This event is in the
Gloabl.asax file.
3. Application_Error: Occurs when an error occurs within the application. This event is
in the Gloabl.asax file.

Methods in the Server object are used to handle the exception in the error events.

1. GetLastError: Gets the last exception that occurred on the server.


2. ClearError: Use this method to handle the exception and stop the error to trigger the
subsequent error event or display the error to the user.

In the following code, you handle the exception in all the above three mentioned events but call
the ClearError method only in the Application_Error event so that the error is propogated to
the above level.

private void Page_Error(object sender, System.EventArgs e)


{
Exception ex = Server.GetLastError();
Response.Write("Handled error from Page<br>");
//Server.ClearError();
}
protected void Application_Error(Object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
Response.Write("Handled error from Application <br>");
Server.ClearError();
}
protected void Global_Error(Object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
Response.Write("Handled error from Global <br>");
}

Using Custom Error Pages

Use custom error page to handle HTTP exceptions such as page not found, unauthorized access,
and so forth. You can specify custom error pages in two places:

1. customErrors section of the web.config file. This setting specifies the application-wide
error page to display for unhandled HTTP errors. HTTP errors are identified by the
HTTP status code. Include the <error> tag in the customErrors to display a status code-
specific error page. Does not work with .htm or .html files. Set the mode attribute to "On"
to view the error page locally.
2. errorPage attribute of the @Page directive of the Web form to display the error page for
the error generated on the particular Web form.

The customsError section in the web.config file specifies the application to redirect to
Error404.aspx file if a non-existent file is requested.

<customErrors mode="On" defaultRedirect="Error.aspx">


<error statusCode="404" redirect="Error404.aspx" />
</customErrors>

The @Page directive specifies the error page to be redirected to if an error occurs in the Web
page.

<%@ Page language="c#" Codebehind="PageErr.aspx.cs"


AutoEventWireup="false"
Inherits="ExceptionHandling.PageErr"
errorPage="Error.aspx" %>

You might also like