When you return a bad request from Controller a global exception is triggered.
Probably a error page is displayed in the client, so jquery get 200 response.
Solution 1:
Controller
[HttpPost]
public ActionResult FooAction(string id, string[] orderFields)
{
bool hasError = true; //TODO: Validation
if (hasError)
{
Response.Clear();
Response.TrySkipIisCustomErrors = true; //the magic
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return Json(new { success = false, message = "test error", status = 500 });
}
else
{
return Json(new { success = true, message = "ok", status = 200 });
}
}
View:
<script type="text/javascript">
$.ajax({
type: "POST",
url: url,
data: { orderFields: order },
success: function (response) {
if (response.success) {
alert("Ok");
}
},
error: function (xhr, status, error) {
if (xhr.responseText != "") {
var err = JSON.parse(xhr.responseText);
if (err.status == 440) {
alert("Session expired");
}
else {
alert(err.message);
}
}
else {
alert("Crash");
}
}
});
</script>
Solution 2:
(More Elegant)
Create a custom attribute
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Net;
using System.Web.Mvc;
public class ExceptionJsonMvcAttribute : FilterAttribute, IExceptionFilter
{
public virtual void OnException(ExceptionContext context)
{
if (context == null)
{
throw new ArgumentNullException("filterContext");
}
if (context.Exception == null)
return;
int status;
string message;
var ex = context.Exception;
var exceptionType = ex.GetType();
if (exceptionType == typeof(UnauthorizedAccessException))
{
var exAccess = (UnauthorizedAccessException)ex;
message = exAccess.Message;
status = (int)HttpStatusCode.Unauthorized;
}
else if (exceptionType == typeof(SqlException))
{
var exSql = (SqlException)ex;
message = GetDbMessage(exSql);
status = (int)HttpStatusCode.BadRequest;
}
else if (exceptionType == typeof(KeyNotFoundException))
{
var exNotFound = (KeyNotFoundException)ex;
message = exNotFound.Message;
status = (int)HttpStatusCode.NotFound;
}
else
{
message = ex.Message;
status = (int)HttpStatusCode.InternalServerError;
}
string json = ""; // TODO: Json(new { success = false, message = message, status = status });
context.ExceptionHandled = true;
context.HttpContext.Response.Clear();
context.HttpContext.Response.TrySkipIisCustomErrors = true;
context.HttpContext.Response.StatusCode = status;
context.HttpContext.Response.ContentType = "application/json";
context.HttpContext.Response.Write(json);
}
private string GetDbMessage(SqlException exSql)
{
//TODO: Remove generic from database
return "DataBase Error see log";
}
}
pay attention for ApiController use System.Net.Http instead of System.Web.Mvc
Controller:
[ExceptionJsonMvc]
[HttpPost]
public ActionResult FooAction(string id, string[] orderFields)
{
bool hasError = true; //TODO: Validation
if (hasError)
{
throw new Exception("test error");
}
else
{
return Json(new { success = true, message = "ok" });
}
}