Javascript
jqXHR = $.ajax({ url: $frm.attr("action"), type: "POST", dataType: "json", cache: false,
headers: headers, contentType: "application/json;charset=UTF-8", data: ko.mapping.toJSON(data, map),
beforeSend: function(x) {
if (x && x.overrideMimeType) {
return x.overrideMimeType("application/json;charset=UTF-8");
}
}
});
jqXHR.fail(function(xhr, err, msg) { /* xhr.responseText NEED TO BE JSON!!! */ });
In Chrome
Headers
Request Method:POST
Status Code:400 Bad Request
Request Headersview source
Accept:application/json, text/javascript, */*; q=0.01
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,pt-BR;q=0.6,pt;q=0.4
Connection:keep-alive
Content-Length:10
Content-Type:application/json;charset=UTF-8
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.117 Safari/537.36
X-Requested-With:XMLHttpRequest
Request Payloadview source {Id:0}
Response Headersview source
Cache-Control:private
Content-Length:54
Content-Type:application/json; charset=utf-8
Date:Thu, 27 Feb 2014 14:01:59 GMT
Server:Microsoft-IIS/8.0
X-AspNet-Version:4.0.30319
X-AspNetMvc-Version:5.1
X-Powered-By:ASP.NET
Response
[{"Name":"Nome","ErrorMessage":"campo obrigatório."}]
Works in chrome!
In IE8
Headers (Request)
POST /Motivos/Salvar HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: pt-br
x-requested-with: XMLHttpRequest
Content-Type: application/json;charset=UTF-8
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)
Content-Length: 10
Connection: Keep-Alive
Pragma: no-cache
Headers (Response)
HTTP/1.1 400 Bad Request
Cache-Control: private
Content-Type: text/html
Server: Microsoft-IIS/8.0
X-AspNetMvc-Version: 5.1
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 27 Feb 2014 13:51:46 GMT
Content-Length: 11
Bad Request
NOT WORK!!
Asp.net MVC
Filter
public class HandleExceptionAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest() && filterContext.Exception != null)
{
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
var ex = filterContext.Exception.GetBaseException();
filterContext.Result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
ex.Message,
ex.GetType().Name
}
};
filterContext.ExceptionHandled = true;
}
else
{
base.OnException(filterContext);
}
}
}
Apply on GlobalFilterCollection
Controller
[ValidateJsonAntiForgeryToken, HttpPost]
public virtual JsonResult Salvar(TViewModel viewModel)
{
if (ModelState.IsValid)
{
TEntity model;
if (default(TKey).Equals(viewModel.Id))
{
model = Mapper.Map<TEntity>(viewModel);
AdicionarEntidade(model, viewModel);
}
else
{
model = Repositorio.Get(viewModel.Id);
Mapper.Map(viewModel, model, typeof(TViewModel), typeof(TEntity));
SalvarEntidade(model, viewModel);
}
return SalvarResult(model);
}
Response.StatusCode = 400;
return Json(ModelState.ToJson(), JsonRequestBehavior.AllowGet);
}
Extenssion
public static object ToJson(this ModelStateDictionary dic, params string[] othersMessages)
{
var states = (from e in dic where e.Value.Errors.Count > 0
select new { Name = e.Key, e.Value.Errors[0].ErrorMessage }).ToList();
if (othersMessages != null)
foreach (var message in othersMessages)
states.Add(new { Name = "", ErrorMessage = message });
return states;
}
Questions
- Why not have the xhr.resposeText object?
- How to retrieve JSON in the same way that I recover in Chrome?
I need the JSON to populate the form!
Notes: 03/11/2014
When I add Response.TrySkipIisCustomErrors = true;
in my controler, it works!
responseText returns the json.
Why?
Think this is an issue with IIS trying to use custom error response rather sending the error message that the controller is generating.
Or
Reference - https://stackoverflow.com/a/4029197/1304559
Check out this blog post http://weblog.west-wind.com/posts/2009/Apr/29/IIS-7-Error-Pages-taking-over-500-Errors
Since response code is set to 400, IIS replaces your content with its custom error page content
I have filled in a fail test that should help.
Specifically look at the error handling in the
.fail
section.Your response comes back with
Content-Type: text/html
http header, but it should beapplication/json
. This is not an issue in Chrome (and you don't get mismatch warnings in the console) because you're relying onoverrideMimeType
... which, you guessed it, is not IE-friendly. In fact, the following is never executed on older versions of IE:Your solution could be to make sure the content is served with correct content type. If you're familiar with tampering tools like Burp Suite, you could add the correct header on-the-fly and see if that fixes the problem. I would probably avoid inlining methods like
AddHeader
and see if there is a way this can be fixed at a higher - routing, perhaps - level.IE (all versions, including IE11) will put "Bad Request" in the status text and ignore the JSON you put in as the message.
In order to use the xhr.responseText in IE on error, you need to throw an exception instead of returning a Json or JsonResult with
HttpStatusCode.BadRequest;
So... before:
This works in Chrome, FF and any sane browser, really. After:
As an unhandled exception, it will be passed to the browser as a response, this will work in Chrome, FF and even in IE. It is not graceful, same as all unhandled exceptions (or just exceptions, for that matter), but it will do the job of letting you receive an appropriate response.
It's not your controller, that's working fine. You're missing a required field: both IE and Chrome are returning status code
400 Bad Request
- but only Chrome is properly processing theresponseText
and giving you[{"Name":"Nome","ErrorMessage":"campo obrigatório."}]
meaning you have a missing form field.Although I've searched all over and haven't found any reference to specific IE bugs in processing
XMLHttpRequest.responseText
with non-200 status codes, it looks like IE is replacing your response body with its own:Indicates that the "content" as it treats it is the "Bad Request" status text, not the proper json response (which Chrome reads as content-length 54, for instance). This might mean IE is discarding your response body (I doubt it, that'd be bloody incredible) or it just isn't be processed "properly." Try dumping the rest of your
jqXHR
object and the arguments for yourfail
handler to see if you can find it in there somewhere.The issue I am seeing is that your trying to set the encoding of the JSON to UTF-8. Normally it works just fine, however, on IIS, it has a custom error to report that the UTF-8 is not necessary.
Few other things to note. You are doing a POST, so the server will be expecting a json file. If provided none, it will not know what to do.