MVC3 return JSON on error instead of HTML [duplicate] - json

How do I handle exceptions thrown in a controller when jquery ajax calls an action?
For example, I would like a global javascript code that gets executed on any kind of server exception during an ajax call which displays the exception message if in debug mode or just a normal error message.
On the client side, I will call a function on the ajax error.
On the server side, Do I need to write a custom actionfilter?

If the server sends some status code different than 200, the error callback is executed:
$.ajax({
url: '/foo',
success: function(result) {
alert('yeap');
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert('oops, something bad happened');
}
});
and to register a global error handler you could use the $.ajaxSetup() method:
$.ajaxSetup({
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert('oops, something bad happened');
}
});
Another way is to use JSON. So you could write a custom action filter on the server which catches exception and transforms them into JSON response:
public class MyErrorHandlerAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
filterContext.Result = new JsonResult
{
Data = new { success = false, error = filterContext.Exception.ToString() },
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
and then decorate your controller action with this attribute:
[MyErrorHandler]
public ActionResult Foo(string id)
{
if (string.IsNullOrEmpty(id))
{
throw new Exception("oh no");
}
return Json(new { success = true });
}
and finally invoke it:
$.getJSON('/home/foo', { id: null }, function (result) {
if (!result.success) {
alert(result.error);
} else {
// handle the success
}
});

After googling I write a simple Exception handing based on MVC Action 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;
filterContext.Result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
filterContext.Exception.Message,
filterContext.Exception.StackTrace
}
};
filterContext.ExceptionHandled = true;
}
else
{
base.OnException(filterContext);
}
}
}
and write in global.ascx:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleExceptionAttribute());
}
and then write this script on the layout or Master page:
<script type="text/javascript">
$(document).ajaxError(function (e, jqxhr, settings, exception) {
e.stopPropagation();
if (jqxhr != null)
alert(jqxhr.responseText);
});
</script>
Finally you should turn on custom error.
and then enjoy it :)

Unfortunately, neither of answers are good for me. Surprisingly the solution is much simpler. Return from controller:
return new HttpStatusCodeResult(HttpStatusCode.BadRequest, e.Response.ReasonPhrase);
And handle it as standard HTTP error on client as you like.

I did a quick solution because I was short of time and it worked ok. Although I think the better option is use an Exception Filter, maybe my solution can help in the case that a simple solution is needed.
I did the following. In the controller method I returned a JsonResult with a property "Success" inside the Data:
[HttpPut]
public JsonResult UpdateEmployeeConfig(EmployeConfig employeToSave)
{
if (!ModelState.IsValid)
{
return new JsonResult
{
Data = new { ErrorMessage = "Model is not valid", Success = false },
ContentEncoding = System.Text.Encoding.UTF8,
JsonRequestBehavior = JsonRequestBehavior.DenyGet
};
}
try
{
MyDbContext db = new MyDbContext();
db.Entry(employeToSave).State = EntityState.Modified;
db.SaveChanges();
DTO.EmployeConfig user = (DTO.EmployeConfig)Session["EmployeLoggin"];
if (employeToSave.Id == user.Id)
{
user.Company = employeToSave.Company;
user.Language = employeToSave.Language;
user.Money = employeToSave.Money;
user.CostCenter = employeToSave.CostCenter;
Session["EmployeLoggin"] = user;
}
}
catch (Exception ex)
{
return new JsonResult
{
Data = new { ErrorMessage = ex.Message, Success = false },
ContentEncoding = System.Text.Encoding.UTF8,
JsonRequestBehavior = JsonRequestBehavior.DenyGet
};
}
return new JsonResult() { Data = new { Success = true }, };
}
Later in the ajax call I just asked for this property to know if I had an exception:
$.ajax({
url: 'UpdateEmployeeConfig',
type: 'PUT',
data: JSON.stringify(EmployeConfig),
contentType: "application/json;charset=utf-8",
success: function (data) {
if (data.Success) {
//This is for the example. Please do something prettier for the user, :)
alert('All was really ok');
}
else {
alert('Oups.. we had errors: ' + data.ErrorMessage);
}
},
error: function (request, status, error) {
alert('oh, errors here. The call to the server is not working.')
}
});
Hope this helps. Happy code! :P

In agreement with aleho's response here's a complete example. It works like a charm and is super simple.
Controller code
[HttpGet]
public async Task<ActionResult> ChildItems()
{
var client = TranslationDataHttpClient.GetClient();
HttpResponseMessage response = await client.GetAsync("childItems);
if (response.IsSuccessStatusCode)
{
string content = response.Content.ReadAsStringAsync().Result;
List<WorkflowItem> parameters = JsonConvert.DeserializeObject<List<WorkflowItem>>(content);
return Json(content, JsonRequestBehavior.AllowGet);
}
else
{
return new HttpStatusCodeResult(response.StatusCode, response.ReasonPhrase);
}
}
}
Javascript code in the view
var url = '#Html.Raw(#Url.Action("ChildItems", "WorkflowItemModal")';
$.ajax({
type: "GET",
dataType: "json",
url: url,
contentType: "application/json; charset=utf-8",
success: function (data) {
// Do something with the returned data
},
error: function (xhr, status, error) {
// Handle the error.
}
});
Hope this helps someone else!

For handling errors from ajax calls on the client side, you assign a function to the error option of the ajax call.
To set a default globally, you can use the function described here:
http://api.jquery.com/jQuery.ajaxSetup.

Related

Why do I get an empty parameter on the controller in my HttpPost method Ajax call?

I have a view that adds an Unordered list and list items to it at runtime, then I loop through to get the entered values, push the info to an object, and do the Ajax call to my method.
I always get an empty parameter on the controller, the console.log(assetWeighJsonDetail) shows what was entered, so I'm making sure I'm not passing and empty object (see the image below):
// Client side script:
var assetSerialNumber = "";
var weight = 0;
var assetWeighJsonDetail = [];
$(".ul-asset-weigh").each(function () {
var classNameSelected = this.id;
$("." + classNameSelected).each(function () {
assetSerialNumber = $(this).attr('id');
weight = $(this).val();
assetWeighJsonDetail.push({
OriginID: classNameSelected,
AssetSerialNumber: assetSerialNumber,
Weight: weight
});
});
});
console.log(assetWeighJsonDetail);
$.ajax({
url: "/AssetWeigh/SaveAssetWeigh",
data: JSON.stringify({assetWeighJsonDetail}),
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
traditional: true,
success: function (response) {
if (response) {
alert("success");
}
else {
alert("fail");
}
},
error: function (exception) {
}
});
// Console:
// Controller Method:
[HttpPost]
public ActionResult SaveAssetWeigh(List<AssetWeighJsonDetail> assetWeighJsonDetail)
{
bool success = false;
success = assetWeighJsonDetail != null && assetWeighJsonDetail.Count > 0;
return Json(success);
}
// Method's class List parameter:
public class AssetWeighJsonDetail
{
public int OriginID { get; set; }
public string AssetSerialNumber { get; set; }
public decimal Weight { get; set; }
}
You should try with $.post I have faced the same issue if using $.ajax and was not working and just switching to $.post made it work.
$.post( "/AssetWeigh/SaveAssetWeigh", parameters, function() {
alert( "success" );
})
.done(function() {
alert( "second success" );
})
.fail(function() {
alert( "error" );
})
.always(function() {
alert( "finished" );
});
I'm on my phone and can't type all of it, I'll try to update later from my computer

How to export JSON to JSP?

I'm having an issue with JSON and JSP. My Java code creates a JSON from a map, like this:
#RequestMapping(value = "/internationalWAExpose", method = RequestMethod.GET)
#ResponseBody
public String exposeWAData(final HttpServletRequest request) {
Map<String, WebAnalyticsDataValue> ajaxDataMap = new HashMap<>();
WAGlobalDataHandler globalHandler = WebAnalyticsFactory.getHandler(WAGlobalDataHandler.class);
globalHandler.setGlobalData(request, "Home", "Content");
ajaxDataMap.putAll(globalHandler.getDataMap());
JSONObject json = new JSONObject();
ajaxDataMap.forEach((k, v) -> {
try {
json.put(k, v);
} catch (JSONException e) {
e.printStackTrace();
}
});
return json.toString();
}
And I need to get the JSON on a JSP to be exposed in the elements section.
So far, I managed to set it in a JS with an Ajax call, but it shows on the console, rather than in the elements section.
AAUI.ajaxRequest({
url: '/home/ajax/internationalWAExpose',
type: 'GET',
dataType: 'json',
timeout: 50000,
onSuccess: function onSuccess(jsonResponse, textStatus) {
var webAnalyticsData = [];
for (var x in jsonResponse) {
webAnalyticsData.push(new KeyValueObject(x, jsonResponse[x]));
}
waTealiumUtils.reportEvent(webAnalyticsData, "view");
},
onError: function onError() {
},
onComplete: function onComplete() {
}
})
Any ideas? Be advised, I'm quite a newbie to JS and JSP.

I can't get the object from action as Json Formatting using ajax post in mvc core

$(document).on("click", "#StudentDelete", function () {
var Id = $(this).attr("data-id");
alert(gelenId);
$.ajax({
url: '/SchoolRepo/DeleteStudent/' + Id,
type: "POST",
datatype: "Json",
success: function (response) {
if (response.Success) {
location.reload();
alert(response.Message);
}
else {
alert(response.Message);
}
}
});
});
public class ResultJson
{
public bool Success { get; set; }
public string Message { get; set; }
}
public IActionResult DeleteStudent(int id)
{
var student = db.Students.FirstOrDefault(q => q.Id == id);
if (student!=null)
{
db.Students.Remove(student);
db.SaveChanges();
return Json(new ResultJson { Message = "Student is deleted successfully", Success=true });
}
return Json(new ResultJson { Message = "Student is not deleted", Success = false });
}
when I use these code snappets I can't get 'Response.Message' or 'Response.Success' values. always returned 'undefined'. when I used the same codes in mvc 5 I could get values. what is the reason ? thank you in advance
JSON result in ASP.NET Core MVC is using camel case naming strategy by default while serializing the result. So the result will get returned as shown below.
{"success":true,"message":"Student is deleted successfully"}
You can access the result as response.success and response.message
I hope this help you.
https://github.com/aspnet/Mvc/blob/760c8f38678118734399c58c2dac981ea6e47046/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonSerializerSettingsProvider.cs

MVC5 Retrieve data with ajax, return json object instead of view

I have a simple function that searches for item I want in my database and retrieves it in my controller.
[HttpPost]
public ActionResult Index(string searchString)
{
var user = from m in db.Users select m;
if (!String.IsNullOrEmpty(searchString))
{
user = user.Where(s => s.UserName.Contains(searchString));
}
return View(user);
}
And then in my Javascript I send a value to search:
$('#test').click(function(e) {
e.preventDefault();
var user = "John";
$.ajax({
url: "#Url.Action("Index", "Users")",
data { "searchString": user },
type: "post",
success: function (saveResult) {
console.log(saveResult);
},
error: function(xhr, ajaxOptions, thrownError) {
console.log(xhr, ajaxOptions, thrownError);
}
})
})
However of course all this does it return my view inside the console window which is something like:
But I would like to return a json object I can use.
just use the Json Action method.
return Json(user);
Edit:
As a side note, I would also set my return Type to be JsonResult for clarity
You just return as JsonResult such as below:
public ActionResult SomeActionMethod() {
return Json(new {foo="bar", baz="Blech"});
}

How to return exception data in json format from App_Error in global.asax?

I'm working on Asp.net MVC project as a single page application for error handling. I want to return json data from Application_Error method in global.asax to UI and show it by jQuery or call a controller and return partialView.
I don't want to refresh the page or redirect it to Error page.
here is the way to go
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
// if the error is NOT http error, then stop handling it.
if (!(exception is HttpException httpException))
return;
if (new HttpRequestWrapper(Request).IsAjaxRequest())
{
Response.Clear();
Response.TrySkipIisCustomErrors = true;
Server.ClearError();
Response.ContentType = "application/json";
Response.StatusCode = 400;
JsonResult json = new JsonResult
{
Data = exception.Message
};
json.ExecuteResult(new ControllerContext(Request.RequestContext, new BaseController()));
}
}
//Write This code into your global.asax file
protected void Application_Error(Object sender, EventArgs e)
{
var ex = Server.GetLastError();
//We check if we have an AJAX request and return JSON in this case
if (IsAjaxRequest())
{
Response.Write(JsonConvert.SerializeObject(new
{
error = true,
message = "Exception: " + ex.Message
})
);
}
}
private bool IsAjaxRequest()
{
//The easy way
bool isAjaxRequest = (Request["X-Requested-With"] == "XMLHttpRequest")
|| ((Request.Headers != null)
&& (Request.Headers["X-Requested-With"] == "XMLHttpRequest"));
//If we are not sure that we have an AJAX request or that we have to return JSON
//we fall back to Reflection
if (!isAjaxRequest)
{
try
{
//The controller and action
string controllerName = Request.RequestContext.
RouteData.Values["controller"].ToString();
string actionName = Request.RequestContext.
RouteData.Values["action"].ToString();
//We create a controller instance
DefaultControllerFactory controllerFactory = new DefaultControllerFactory();
Controller controller = controllerFactory.CreateController(
Request.RequestContext, controllerName) as Controller;
//We get the controller actions
ReflectedControllerDescriptor controllerDescriptor =
new ReflectedControllerDescriptor(controller.GetType());
ActionDescriptor[] controllerActions =
controllerDescriptor.GetCanonicalActions();
//We search for our action
foreach (ReflectedActionDescriptor actionDescriptor in controllerActions)
{
if (actionDescriptor.ActionName.ToUpper().Equals(actionName.ToUpper()))
{
//If the action returns JsonResult then we have an AJAX request
if (actionDescriptor.MethodInfo.ReturnType
.Equals(typeof(JsonResult)))
return true;
}
}
}
catch
{
}
}
return isAjaxRequest;
}
//Write this code in your ajax function in html file
<script type="text/javascript">
$.ajax({
url: Url
type: 'POST',
data: JSON.stringify(json_data),
dataType: 'json',
cache: false,
contentType: 'application/json',
success: function (data) { Successfunction(data); },
error: function (xhr, ajaxOptions, thrownError) {
var obj = JSON.parse(xhr.responseText);
if (obj.error) {
show_errorMsg(obj.message);
}
}
});
</script>