views:

84

answers:

3

I have some jQuery that looks like this:

$.ajax({
     type: "POST",
     url: "/Customer/CancelSubscription/<%= Model.Customer.Id %>",
     contentType: "application/json",
     success: refreshTransactions,
     error: function(xhr, ajaxOptions, thrownError) {
         alert("Failed to cancel subscription! Message:" + xhr.statusText);
     }
});

If the action being called causes an exception it will ultimately get picked up by the Global.asax Application_Error where I have some code like this:

var ex = Server.GetLastError();
if (Request.ContentType.Contains("application/json"))
{
     Response.StatusCode = 500;
     Response.StatusDescription = ex.Message;
     Response.TrySkipIisCustomErrors = true;
}
else
{
     // some other way of handling errors ...
}

When I execute the script that does the post the Request.ContentType is always an empty string and therefore does not hit the first if block. Is there some other value that I should be putting in the ajax "contentType"? Or is there another way for me to tell asp.net that the content type should be "application/json"?

Clarification

The goal I am trying to achieve is to pass the exception message back to the ajax error event. Currently, even though the IF block is being bypassed, the error event correctly throws an alert box but the message is "Not Found".

As you can see I am trying to set the exeception message to the Response.StatusDescription which I believe the xhr.statusText in the ajax error is set to.

+2  A: 

To set custom headers in the XmlHTTPRequest, you need to utilize the beforeSend() option function in the jQuery AJAX Call. Use that function to set additional headers, as described in the jQuery API documenation.

Example:

  $.ajax({
    type: "POST",
    url: "/Customer/CancelSubscription/<%= Model.Customer.Id %>",
    beforeSend: function(xhr) {
      xhr.setRequestHeader( "Content-type", "application/json" );
    },
    success: refreshTransactions,
    error: function(xhr, ajaxOptions, thrownError) {
       alert("Failed to cancel subscription! Message:" + xhr.statusText);
    }
  });
Michael Bray
This worked, thank you. I had read the API but I don't really see how what you have in your example compares to what they describe. Your sample is much more thorough than what they have.
Sailing Judo
A: 

If you are always returning json for Ajax errors, then you can just use the following to detect that it is an Ajax call:

// jQuery sets a header of 'x-requested-with' in all requests
            string[] ajaxHeader = httpRequest.Headers.GetValues("x-requested-with");
            if (ajaxHeader != null && ajaxHeader.Length > 0)
            {
                return ajaxHeader[0].Equals("XMLHttpRequest", StringComparison.InvariantCultureIgnoreCase);
            }
            return false;
Keith Rousseau
+5  A: 

Accordiing to this article: http://encosia.com/2008/03/27/using-jquery-to-consume-aspnet-json-web-services/ "jQuery does not properly set the specified content-type when there is no data included. "

$.ajax({
  type: "POST",
  contentType: "application/json; charset=utf-8",
  url: "WebService.asmx/WebMethodName",
  data: "{}",
  dataType: "json"
});
Typeoneerror
This changed in jQuery 1.4, now it always sends the content type...important note :) http://api.jquery.com/jQuery.ajax/
Nick Craver
I tested this method out and it does work. We are using jQuery 1.3.2 here. From what Nick describes it sounds like my code in the question should work with 1.4.
Sailing Judo
This is the correct answer. Modifying the XHR object's content-type setting in beforeSend doesn't work right in some browsers, and the service will return XML instead of JSON.
Dave Ward
the more i look at it the more i agree that this is the more correct answer. judging by the upvotes others agree. i'll change the selected answer.
Sailing Judo