17

I am using ASP.NET MVC for developing a web site. I am using jquery for AJAX functionality. In the action methods, I want to return some error to signal that the input is not correct or that the action could not be performed. In such error cases, I expect the jquery ajax error handler to be called and I can take appropriate action in there. I have not found a way how to do this. Following is my action method.

In error cases, what should I be sending from an Action in order to get the jquery error handler triggered?

public ActionResult AddToFavourites(int entityId, string entityType)
    {

        if (!Request.IsAjaxRequest())
            throw new InvalidOperationException("This action can be called only in async style.");

        try
        {
            RBParams.EntityType typeOfFavourite = (RBParams.EntityType)Enum.Parse(typeof(RBParams.EntityType), entityType);
            string status = "";

            if (typeOfFavourite == RBParams.EntityType.BusinessEntity)
            {
                status = MarkFavouriteEntity(entityId);
            }
            else if (typeOfFavourite == RBParams.EntityType.Review)
            {
                status = MarkFavouriteReview(entityId);
            }
            else
            {
                throw new InvalidOperationException("The type of the entity is not proper");
            }

            return Content(status);

        }
        catch (Exception ex)
        {

            return Content("Error");
        }
    }
DaveRandom
  • 87,921
  • 11
  • 154
  • 174
dotcoder
  • 2,828
  • 10
  • 34
  • 50

3 Answers3

24

Your ajax error handler will be called when the action doesn't return a expected status code. It will, for example, fire if the action wasn't found or if you throw a exception that you don't handle. In your case it will be called if you don't catch the error in your action (as the action will return a 500 status code).

I would, however, not do it in this way as this is probably a expected error. I would rather return json both when you succeed and when you have a error. Then you can indicate if it is a successful call or not. Something like this:

public ActionResult AddToFavourites(int entityId, string entityType)
{

    if (!Request.IsAjaxRequest())
        throw new InvalidOperationException("This action can be called only in async style.");

    try
    {
        RBParams.EntityType typeOfFavourite = (RBParams.EntityType)Enum.Parse(typeof(RBParams.EntityType), entityType);
        string status = "";

        if (typeOfFavourite == RBParams.EntityType.BusinessEntity)
        {
            status = MarkFavouriteEntity(entityId);
        }
        else if (typeOfFavourite == RBParams.EntityType.Review)
        {
            status = MarkFavouriteReview(entityId);
        }
        else
        {
            throw new InvalidOperationException("The type of the entity is not proper");
        }

        return Json(new { Success = true, Status = status });

    }
    catch (Exception ex)
    {

        return Json(new { Success = false, Message = ex.Message });
    }
}

Then you handle it in the same way as a successful call. You just check the Success property of your json response. Then you handle unexpected errors in the error callback.

Mattias Jakobsson
  • 8,207
  • 2
  • 34
  • 41
  • Are the `Json` settings provided in your example gonna be set to the client's `xhr` variables? – Shimmy Weitzhandler Jul 07 '13 at 23:51
  • 3
    I didn't downvote, but I disagree. (Sorry, @Mattias). This'll cause the JavaScript "success" callback to fire. We always want the error callback to fire when there's an error on the server. This violates symantics. Symantically, we'd want to return a 500-series error. – Rap Jan 12 '14 at 17:20
  • 1
    You can return an error with Response.StatusCode = (int) HttpStatusCode.InternalServerError; just before the return Json(...); – Rap Jan 12 '14 at 17:48
  • 1
    You can also throw an HttpException. e.g., throw new HttpException(HttpStatusCode.InternalServerError, ex); That will trigger the ajax error callback and provide an explanation of the problem. – grahamesd Mar 31 '14 at 19:07
  • I did used to do something like the answer and while it works... with Web Api I've used action filter attributes that catch the exception and return an error code with the different detail levels (different error codes for expected errors vs unexpected) makes the client side more sane... none of this error is a success madness! :) +1 for HttpException sounds like the answer I came looking for this time! – PJUK Jul 13 '14 at 13:20
12

Mattias Jakobsson's answer is right. But I think the best way to return the error to the jQuery is creating a JSON and sending it with status 500. However, when I did it and tried to deploy my MVC website using IIS 7 I figured out that it was returning me the custom page instead of the message.

The code was...

catch (Exception ex)
{
    Response.StatusCode = 500;
    return Json(new { error = ex.Message });
}

But then I saw this thread that led me to this web site (from Rick Strahl).

Overall, I understood that you need to say to IIS to not inject the custom error page, so you need this flag (in the global.asax or into the catch):

Response.TrySkipIisCustomErrors = true;

So, in jQuery the code keeps the same:

$.ajax({...})
.done(function (result) {...})
.fail(function (e) { 
   console.log(e.responseJSON.error);
});
Community
  • 1
  • 1
  • 2
    This is an excellent and complete answer. You show an example of the controller **and** the corresponding AJAX call. Thanks for taking the time. – Doppelganger Jun 13 '16 at 18:42
0

you shoud config jquery to handle error:

$.ajaxSetup({
    error: function(xhr) {
        alert(xhr.statusText);
    }
})
ldp615
  • 932
  • 1
  • 9
  • 13
  • 2
    Ild615, I had done this in the $.ajaxSetup(...). My issue is what should I be sending from Action to get this error handler triggered. – dotcoder Mar 04 '10 at 09:29