Introduction
Who is this article for?
- You should know the basics of jquery Ajax and ASP MVC.
- So you know how to make Ajax call, but you want to learn how to handle Ajax errors properly? What to do if there is an unauthorized Ajax call? Then go on with reading.
I’d like to show you simple Add Entity demo with proper Ajax error handling:
1. Controller Action
[HttpPost]
public ActionResult Add(Entity entity)
{
var valid = Validate(entity);
if(!valid)
{
return new HttpStatusCodeResult(400, "You can't add this entity.");
}
return this.Add(entity); }
2. JavaScript
function add()
{
var isvalid = $("#form").valid();
if (!isvalid)
{
return;
}
$.ajax({
url: addUrl,
data: $("#form").serialize(),
type: "POST",
dataType: "html"
})
.success(function (result, status) {
$("#entities").html(result);
})
.error(function (xhr, status) {
if (xhr.status == 401)
{
window.location = unauthorizedUrl; }
if (xhr.statusText == null || xhr.statusText == "") {
showError("There was an error while adding Entity.
Please try again."); }
else {
showError(xhr.statusText); }
});
}
We have two callbacks:
success:
- When everything goes fine, show updated list of entities.
error:
- This is a part that is more interesting. Something happens in the application and we want to handle the error.
Let's take it from the bottom:
- Status is not 401 and there is a
statusText
in response (we have send message in response):
- showError(xhr.statusText);
- Status is not 401 but there is no
statusText
(we haven’t send any message in response):
- showError("There was an error while adding Entity.
Please try again.");
- Status is 401:
- window.location = unauthorizedUrl;
However this will not work, without a little hack.
401 means unauthorized request. MVC framework will automatically look for this in your app and will redirect you(302=redirect) to your unauthorized error page. And then will return this page (200 = success). So that means you will end up in success callback and instead of your PartialView
with updated entities you will get your unauthorized page. So how to override this default behaviour?
In your Startup
class, just add:
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 302 &&
Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
{
Context.Response.Clear();
Context.Response.StatusCode = 401;
}
}
This solution is not 100% bullet proof. If you look at the code, it basically checks your response and if there is 302 code (redirect) and also it is Ajax call. It will change the status code to 401(unauthorized). So there might be case in your app where you want to return 302 code and this piece of code would break it. In such case, you would have to use some kind of identifier that would differentiate those responses.
Summary
You should always add at least some general error handling for your Ajax calls. It will help you to debug and test your application and it will help your users to identify that there is something wrong in case of error.