1.4. Other Exception Handling Scenarios

You've already learned how to handle exceptions in your own code. However, ASP.NET has several components that do their work behind the scenes. Since this is code that you don't write yourself, you can't very well stick a try-catch block in there. So, how do you deal with errors that occur in these components? Let's take a look at a few common scenarios.

1.4.1. Handling Exceptions in ASP.NET Data Sources

As you know, you can use data source controls to bind ASP.NET server controls to data. When you do that, the methods that do the actual work are invoked automatically by the data source control. For example, the business object method specified in the SelectMethod property of an ObjectDataSource is invoked automatically when the DataBind method is called on a server control that uses that ObjectDataSource. Automatic method invocation takes place in a similar fashion for other data operations, like inserting, updating, and deleting records.

To determine if an exception was thrown while executing a method from a data source, you can handle the event that signals that the operation has been completed. For example, to see if an exception was thrown by the business object method specified in SelectMethod, you would handle the Selected event of the ObjectDataSource. Of course, for other data operations, you would handle that operation's corresponding event, such as Inserted, Updated, or Deleted. Once you establish that an exception was, indeed, thrown, you can determine its type and respond accordingly.

Listing 13 shows an example of handling an exception thrown by the SelectMethod of an ObjectDataSource.

Example 13. Exception handling in an ObjectDataSource
protected void odsProducts_Selected(object sender,
                                    ObjectDataSourceStatusEventArgs e)
{
   if (e.Exception != null)
   {
      if (e.Exception.InnerException is InvalidOperationException)
      {
         litResult.Text = "An improper connection string was supplied.";
      }
      e.ExceptionHandled = true;
   }
   else
   {
      litResult.Text = "There were " + Product.GetProductCount() +
                       " products found.";
   }
}

You see that the handler for the Selected event provides access to an ObjectDataSourceStatusEventArgs object that has an Exception property. This property contains any exception that may have been thrown while executing the SelectMethod. If no exception was thrown, this property is null. You can test the value, and if it is not null, provide code to handle the exception.

You need to be aware that with data source controls, the main exception exposed by the Exception property will not be the actual exception that was thrown by the underlying method. That's because the delegate that raises the Selected event always wraps the thrown exception in a new TargetInvocationException. To get to the actual exception, you need to use the InnerException property.

Remember, because you're not actually "catching" the exception in a catch block, the exception will continue to bubble up the call stack. To halt exception propagation, you need to set the ExceptionHandled property of the ObjectDataSourceStatusEventArgs object to true.

While this example only deals with selecting records from an ObjectDataSource, the process works the same for other data operations and for other data sources.

1.4.2. Handling Exceptions in ASP.NET Data-Bound Controls

In addition to the technique just presented, you also have the option of handling an exception directly from the data-bound control itself. This comes in handy in situations in which you might not be using a data source control, but instead setting the DataSource property of a control directly, then explicitly calling the DataBind method.

Listing 14 shows how to handle an exception from the RowUpdated event of a GridView.

Example 14. Exception handling in a GridView
protected void gvProducts_RowUpdated(object sender,
                                     GridViewUpdatedEventArgs e)
{
   if (e.Exception != null)
   {
      litResult.Text =
         "An error occurred while updating the row. Please try again.";

      e.ExceptionHandled = true;
      e.KeepInEditMode = true;
   }
   else if (e.AffectedRows == 0)
   {
      litResult.Text =
         "No rows were updated. Another user may have updated that product." +
         " Please try again.";
   }
}

You'll notice that the procedure is not much different from the previous example.

1.4.3. Handling Exceptions in ASP.NET Rich Server Controls

ASP.NET provides a number of so-called rich server controls that abstract complex functionality away from the developer. These controls must often interact with data providers or other core objects to carry out various operations. These server controls raise events in response to errors that occur when those operations fail. You can use these events to deal with the error.

For example, the CreateUserWizard serves as a front-end for a MembershipProvider object, which provides an API for working with users. When the membership data store throws an exception such that the underlying provider fails to create the user, a chain of events take place that culminates in the CreateUserWizard raising its CreateUserError event. Along the way, information about the exception is encapsulated in a CreateUserErrorEventArgs object. Listing 15 shows one way to handle the CreateUserError event.

Example 15. Exception handling in a CreateUserWizard control
protected void CreateUserWizard1_CreateUserError(object sender,
                                                 CreateUserErrorEventArgs e)
{
   switch (e.CreateUserError)
   {
      case MembershipCreateStatus.DuplicateUserName:
         litResult.Text =
            "That user name is taken. " +
            "Please enter a different user name.";
         break;

      case MembershipCreateStatus.InvalidUserName:
         litResult.Text =
            "The user name provided is invalid. " +
            "Please check the value and try again.";
         break;

      case MembershipCreateStatus.DuplicateEmail:
         litResult.Text =
            "A user with that e-mail address already exists. " +
            "Please enter a different e-mail address.";
         break;

      case MembershipCreateStatus.InvalidPassword:
         litResult.Text =
            "The password provided is invalid. " +
            "Please enter a valid password.";
         break;

      case MembershipCreateStatus.InvalidEmail:
         litResult.Text =
            "The e-mail address is invalid. " +
            "Please check the e-mail address and try again.";
         break;

      case MembershipCreateStatus.InvalidAnswer:
         litResult.Text =
            "The password retrieval answer provided is invalid. " +
            "Please check the answer and try again.";
         break;

      case MembershipCreateStatus.InvalidQuestion:
         litResult.Text =
            "The password retrieval question provided is invalid. " +
            "Please check the question and try again.";
         break;

      case MembershipCreateStatus.ProviderError:
      case MembershipCreateStatus.UserRejected:
         litResult.Text =
            "An error occurred. The user was not created. " +

"Please verify your input and try again.";
         break;

      default:
         litResult.Text =
            "An unknown error occurred. " +
            "Please verify your input and try again.";
         break;
   }
}

The CreateUserError event handler in Listing 15 uses the CreateUserError property of the passed-in CreateUserErrorEventArgs object to determine what error has occurred and notifies the user accordingly. The CreateUserError property is an enumeration of type MembershipCreateStatus, which contains all the possible outcomes from an attempt to create a user.

1.4.4. Handling Exceptions in Asynchronous Postbacks

Listing 16 shows one way to handle an exception that occurs during the execution of an AJAX postback.

Example 16. Exception handling from an asynchronous postback
<asp:ScriptManager ID="ScriptManager1" runat="server"
   AllowCustomErrorsRedirect="false" />
...

<script type="text/javascript">

   Sys.WebForms.PageRequestManager
      .getInstance().add_endRequest(OnEndRequest);

   function OnEndRequest(sender, args) {
      var errorElement = $get("errorMessage");

      if (args.get_error()) {
         errorElement.innerHTML =
            "An error occurred while attempting to fulfill your request. " +
            "Please try again.";
         args.set_errorHandled(true);
      }
      else {
         errorElement.innerHTML = "";
      }
   }

</script>

By default, if an error occurs during an asynchronous postback and you've configured the ASP.NET default exception handler (which we'll discuss in detail shortly), the exception will bubble up to the runtime and will be processed just as any other unhandled exception would be. This means that if you intend to handle the exception on the client side, you should disable this behavior. You do that by setting the AllowCustomErrorsRedirect property of the ScriptManager to false, as shown in Listing 16.

The PageRequestManager.endRequest client-side event is raised after an asynchronous response is received, whether or not an error actually occurs. In Listing 16, inside the script tags, you wire up an event handler for the endRequest event. The args parameter of the handler accepts an argument of type EndRequestEventArgs, which has two relevant properties: error, which represents any error that may have occurred while processing the request; and errorHandled, which allows you to stop the error from reaching the AJAX server-side runtime.

This particular handler assumes you have some client-side element — a span, div, paragraph, or whatever — that can contain HTML that displays an error message, and that specifies id="errorMessage" in its tag. If an error occurs during the postback, a reference is obtained to that element, its HTML is set to an appropriate error message, and the error is suppressed. If no error occurs, the element's HTML is cleared, and no error message is displayed.

Keep in mind that you can also handle AJAX errors on the server side by handling the ScriptManager.OnAsyncPostBackError event. The AsyncPostBackErrorEventArgs object that is passed to this event handler lets you access the exception through its Exception property. However, since most browsers (other than Internet Explorer) don't display any readily available user feedback in response to error messages sent from the AJAX server-side runtime, you'll usually find it more useful to implement client-side error handling as shown in Listing 16.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.15.43