Monday, May 3, 2010

jQuery Ajax Error Handling – How To Show Custom Error Messages

Books I recommend on this subject

The following books are the best references I have found when working with jQuery and ASP.NET MVC. I highly recommend both.

jQuery in Action

Pro ASP.NET MVC Framework

So you want to make your error feedback nice for your users…

Kind of an ironic statement isn’t it? We obviously want to avoid errors if at all possible in our applications, but when errors do occur then we want to provide some nice feedback to our users. The worst thing that can happen is to blow up a huge server exception page when something goes wrong or equally bad is not providing any feedback at all and leaving the user in the dark. Although I do not recommend displaying actual .NET Framework exception messages or stack traces to the user in most instances; they are usually not helpful to the user and can be a security concern.

Using the jQuery Ajax methods ($.ajax(), $.get(), $.post(), etc.) to call your controller (in ASP.NET MVC) or web service (in ASP.NET) to perform server side actions (GET, POST, etc.) is a great way to provide a great user experience in ASP.NET applications while also interacting with a server to get or update data. However, if an error occurs on the server, or an exception takes place in the server side methods, then the problem can often be hidden from the user. Because a Postback is not taking place, if you do not handle errors on the jQuery Ajax methods and display some feedback then the user will be left in a state where they have no idea that a problem has occurred. Luckily, we can use the error callback on the jQuery Ajax methods along with some controller information to display some nice error feedback to the user.

Setting up layers to handle and communicate problems

I have defined an Entities assembly that contains an object to be used to provide operation feedback between assemblies and methods.

namespace jQueryCustomErrorHandling.Entities
{
public class OperationResult
{
public bool Success { get; set; }
public string Message { get; set; }
}
}

My persistence and logic methods pass an OperationResult as a return type.

Persistence Layer 

public interface IMyDao
{
OperationResult MyDaoMethod(bool fail);
}
public class MyDao : IMyDao
{
public OperationResult MyDaoMethod(bool fail)
{
var result = new OperationResult() { Success = true };
try
{
if (fail)
throw new Exception("Persistance Error");
}
catch (Exception ex)
{
result.Success = false;
result.Message = ex.Message;
}
return result;
}
}

Logic Layer

public interface IMyLogic
{
OperationResult MyLogicMethod(bool fail);
}
public class MyLogic : IMyLogic
{
private IMyDao _myDao;
public IMyDao MyDao
{
get { return _myDao ?? (_myDao = new MyDao()); }
set { _myDao = value; }
}
public OperationResult MyLogicMethod(bool fail)
{
return MyDao.MyDaoMethod(fail);
}
}

And now communicating the errors to the presentation layer

I have created a controller method that calls the logic layer. Notice that if the OperationResult.Success property is set to false, I throw an exception in the controller method. The catch block handles that exception and sets the Response.StatusCode to an error and then also does a Response.Write of the error message. This is how we communicate with the jQuery error callback that there was an error on the server side.

[AcceptVerbs(HttpVerbs.Post)]
public JsonResult MyPostMethod(bool fail)
{
try
{
// Call the logic layer to make the updates
OperationResult result = MyLogic.MyLogicMethod(fail);
// If the result is a failure, throw an exception
if (!result.Success)
throw new Exception(result.Message);
return Json(result.Message);
}
catch (Exception ex)
{
string errorMsg = string.Format("Error posting data: {0}", ex.Message);
Response.StatusCode = 500;
Response.Write(errorMsg);
return Json(string.Empty);
}
}

The jQuery.ajax configuration looks like this:

function CallAjaxMethod(fail) {
$('#lblMethodError').hide();
$('#lblMethodSuccess').hide();
$.ajax({
type: "POST",
url: "/Home/MyPostMethod",
data: "fail=" + fail,
dataType: "json",
error: function(xhr, status, error) {
// Show the error
$('#lblMethodError').text(xhr.responseText);
$('#lblMethodError').show();
},
success: function(data, textSuccess) {
// show the success message
$('#lblMethodSuccess').show();
}
});
}

The presentation

In the view I simply have two hidden labels that I show or hide depending on whether or not the jQuery.ajax call was successful. I populate the error label with the custom error message from the server in the jQuery.ajax error callback if a problem occurred on the server side.

This provides a nice way to give feedback to the user when problems occur on the server side and also establishes a nice error handling pattern within your projects.

Demo download

I put together a working demo with full source code that you can download below.

- Aaron Schnieder
http://www.churchofficeonline.com

2 comments:

Cristovão said...

But with JSONP nothing works :S

Pravin Kittappa said...

Thanks for this.
I used the same in java.
httpServletResponse.setStatus(HttpServletResponse. SC_INTERNAL_SERVER_ERROR);
httpServletResponse.getWriter().write("Error occured while using Favorite Address.");

Enabled control to go the error callback of jquery ajax. And am able to get the error message set, by calling XMLHttpRequest.responseText