I'm building a RESTful web api with asp.net mvc, which returns pure json data. On my client, I'm using backbone.js to communicate to it.
My question is, how do I capture the message in javascript? For eg. What if a user has no permission to delete or there was no item matching the id? I've been told to throw http errors instead of custom json.
So my code would be:
[HttpDelete]
public ActionResult Index(int id)
{
if (id == 1)
{
throw new HttpException(404, "No user with that ID");
}
else if (id == 2)
{
throw new HttpException(401, "You have no authorization to delete this user");
}
return Json(true);
}
How do I access the message in my javascript callback? The callback would look like:
function (model, response) {
alert("failed");
//response.responseText would contain the html you would see for asp.net
}
I do not see message i threw in the exception anywhere at all in the data that was returned from the server.
You should use the error callback on the client. The success callback is triggered only when the request succeeds:
$.ajax({
url: '/home/index',
type: 'DELETE',
data: { id: 1 },
success: function (result) {
alert('success'); // result will always be true here
},
error: function (jqXHR, textStatus, errorThrown) {
var statusCode = jqXHR.status; // will equal to 404
alert(statusCode);
}
});
Now there is a caveat with 401 status code. When you throw 401 HTTP exception from the server, the forms authentication module intercepts it and automatically renders the LogIn page and replaces the 401 status code with 200. So the error handler will not be executed for this particular status code.
I just answered this in my question What is the point of HttpException in ASP.NET MVC, but you can actually get that string if you use the HttpStatusCodeResult like this:
In your controller:
return new HttpStatusCodeResult(500,"Something bad happened")
And you can access "Something bad happened" using, say, jQuery $.ajax() like this:
$.ajax: {
url: "#Url.Action("RequestsAdminAjax", "Admin")",
type: "POST",
data: function(data) { return JSON.stringify(data); },
contentType: "application/json; charset=utf-8",
error: function (xhr, textStatus,errorThrown) {
debugger;
toggleAlert('<strong>Error: </strong>Unable to load data.', 'alert alert-danger');
}
},
and errorThrown will contain "Something bad happened".
HTH.
Related
I have a form that I am submitting using AJAX:
var formData = JSON.stringify($('#supportrequest').serializeArray());
$.ajax({
type: "POST",
url: "/updatesupportrequest?bugid=" + $('#requestnum').val(),
data: formData,
success: function(){
console.log("success");
},
error: function(xhr, status, error) {
console.log(xhr);
console.log(status);
console.log(error);
},
complete: function(){
console.log("complete");
},
dataType: "json",
contentType : "application/json"
});
This is picked up by my Spring Boot controller:
#PostMapping("/updatesupportrequest") // Called by the form
public String createSupportRequest(#RequestParam(name = "bugid") int bugid, #RequestBody String requestBody,
Model model) {
System.out.println(bugid);
DatabaseWriteResponse response = writeToDatabaseService
.writeToDatabase(WriteToDatabaseService.PROCEDURE_UPDATESUPPORTREQUEST, requestBody);
System.out.println(response.getResponse());
if (response.getResponse().equals(DatabaseWriteResponse.SUCCESS)) {
return "supportrequest";
}
else {
model.addAttribute("response", response.getResponse());
model.addAttribute("errorMsg", response.getMsg());
return "error";
}
}
The actual saving of the data works just fine. The problem is that the controller returns the "supportrequest.html" page. AJAX then throws a parse error:
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
Looking at the xhr.responseText, we get the page back:
responseText: "<!--\r\n TODO\r\n - Dev page has some different fields \r\n\r\n\r\n -->\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n<head>\r\n<title>Support Center</title>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html;
I either need the page to redirect properly (which works fine on Get, just not Post) or to be able to return an empty JSON string and trigger the AJAX success function. I don't particular care which - I can handle the result either way. I just can't get either option to work. What am I doing wrong?
If you want to return JSON in a #Controller class, then annotate the return type of the method with #ResponseBody.
In typescript I have a DataAccess Class so that all Ajax calls are routed through a single object to save repetition of code in a lot of places within my application.
In using this approach I have needed to use call backs to get the response back to the calling class so that the success and error can be handled accordingly.
This is the typescript
ajaxCall(retVal, retError) {
$.ajax({
type: this.callType,
data: this.dataObject,
dataType: this.dataType,
url: this.url,
contentType: this.contentType,
traditional: this.traditional,
async: this._async,
error: retError,
success: retVal
});
}
This is the compiled Javascript
AjaxDataAccessLayer.prototype.ajaxCall = function (retVal, retError) {
$.ajax({
type: this.callType,
data: this.dataObject,
dataType: this.dataType,
url: this.url,
contentType: this.contentType,
traditional: this.traditional,
async: this._async,
error: retError,
success: retVal
});
};
return AjaxDataAccessLayer;
This calls through to the ASP.Net MVC controllers perfectly fine, however the problem that I have is regardless of Success or Error the call back is always retError.
This is the calling Typescript
var _this = this;
var dataAccess = new DataAccess.AjaxDataAccessLayer(Fe.Upsm.Enums.AjaxCallType.Post,
Fe.Upsm.Enums.AjaxDataType.json,
"../../PrintQueue/DeletePrintQueueItems",
jsonObj);
dataAccess.ajaxCall(data => {
// success
new Fe.Upsm.Head().showGlobalNotification("Selected Items Deleted");
_this.refreshPrintQueueGrid();
(window as any).parent.refreshOperatorPrintQueueCount();
}, xhr => {
// failure
alert("An Error Occurred. Failed to update Note");
});
When stepping through and looking at this the Status is OK and the response is 200.
So, Problem (as mentioned above) always calling xhr \ retError regardless of success.
Question: How do I get it to go into the right call back?
In your error handler, you were not passing all the parameters, so you are only checking whether the request finished successfully. However, there can be errors after that, like when the response is processed. You can handle errors betters like this:
dataAccess.ajaxCall(data => {
// success
new Fe.Upsm.Head().showGlobalNotification("Selected Items Deleted");
_this.refreshPrintQueueGrid();
(window as any).parent.refreshOperatorPrintQueueCount();
}, (xhr, errorText, errorThrown => {
// failure
console.log(xhr, errorTest, errorThrown);
alert("An Error Occurred. Failed to update Note");
});
Based on the discoveries using this method, the error is that your controllers are returning empty responses, so you're getting an exception when jQuery tries to parse them, because an empty string is not valid JSON.
AJAX error is being returned as Success. How to return JSON error from ASP.NET MVC? Could you tell me what I'm doing wrong? Thank you.
[HttpPost]
public JsonResult Register(int EventID)
{
try
{
// code
return Json(new { success = true, message = "Thank you for registering!" });
}
catch (Exception ex)
{
return Json(new { success = false, message = ex.Message });
}
}
$.ajax({
url: "#Url.Action("Register", "Home")",
type: "post",
dataType: "json",
contentType: "application/json",
data: JSON.stringify(postData),
success: function(data) {
},
error: function (data) {
}
});
The error function gets executed only when the HTTP Response Code is not HTTP 200 Ready. You handle the error in the server-side and return proper response, which will be picked up by success function in the AJAX call. Instead, use the status variable in your JSON and handle it on the client side:
success: function(data) {
if (typeof data == "string")
data = JSON.parse(data);
if (data.success) {
// Code if success.
} else {
// Code if error.
}
},
From the docs (scroll down to the error section):
A function to be called if the request fails. The function receives three arguments: The jqXHR (in jQuery 1.4.x, XMLHttpRequest) object, a string describing the type of error that occurred and an optional exception object, if one occurred. Possible values for the second argument (besides null) are "timeout", "error", "abort", and "parsererror". When an HTTP error occurs, errorThrown receives the textual portion of the HTTP status, such as "Not Found" or "Internal Server Error." As of jQuery 1.5, the error setting can accept an array of functions. Each function will be called in turn. Note: This handler is not called for cross-domain script and cross-domain JSONP requests. This is an Ajax Event.
The Ajax error method is hit only when you get a Yellow Screen Error in the server side. In your scenario you are handling the error using try catch and returning a valid response. So this is not considered as a error but a valid response. Remove your try catch so that Ajax will pick up the error event, else if you want to show the actual error message from server then you can use the success property to decide if the response was a success or a error , its similar to what Praveen has already posted in his answer.
success: function(data) {
if (data.success) { //as you are passing true/false from server side.
// Code if success.
} else {
// Code if error.
}
},
I'm using angularjs to call my Rest web services but I have a problem with error handle.
This is one of my http calls:
$http({
method: 'POST',
url: "tr"+licenseSelected,//angular need string in url
headers: {'Content-Type': 'application/json'},
data : updatedLicense,
beforeSend: function() {
waitingModal.showPleaseWait();
},
complete: function() {
setTimeout(function(){
waitingModal.hidePleaseWait();
}, 1000);
}
}).then(function successCallback(response) {
if (response.data.success==true){
licenseTable.ajax.reload();
$('#updateLicenseModal').modal("hide");
notifyMessage(response.data.result, 'success');
} else {
notifyMessage(response.data.result, 'error');
}
}, function errorCallback(response) {
window.location.href = "/ATS/500";
});
I would like to show 500 page if an error occurred during http request (for example server down or wrong url), but errorCallback is never called.
Is there an error in my code? where is my fault?Thanks
This is an example of response that I can't handle in error code:
{
"status":422,
"exception":"org.springframework.web.method.annotation.MethodArgumentTypeMismatchException",
"message":"Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: \"tr71\"",
"stacktrace":"org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: \"tr71\"
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:115)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:78)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:129)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:111)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806)
......"
}
Web service example
#Override
#RequestMapping(value = { "/license"}, method = RequestMethod.POST)
public #ResponseBody Response createLicense(#RequestBody ClientLicenseForm clientLicenseForm) {
try{
administrationService.createLicense(clientLicenseForm);
return new Response(true, true, "Your license has been created!", null);
}catch(Exception e){
ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(e);
LOG.error("Threw exception in AdministrationControllerImpl::createLicense :" + errorResponse.getStacktrace());
return new Response(false,false,"Error! Your license hasn't been created!",errorResponse);
}
}
This may be the problem(it wrap json response inside another object), but how can I fix it?
UPDATE
I have fixed with this code, I'll test it
}).then(function successCallback(response) {
if (typeof response.data.success == 'undefined'){
window.location.href = "/ATS/500";
}else if (response.data.success==true){
licenseTable.ajax.reload();
$('#updateLicenseModal').modal("hide");
notifyMessage(response.data.result, 'success');
} else if(response.data.success==false) {
notifyMessage(response.data.result, 'error');
}
}, function errorCallback(response) {
window.location.href = "/ATS/500";
});
Redarding you comments you get a json response (i think with 200 header)
The error callback will not fire while in the header response was 200 code.
You can manage it in two ways:
Rewrite backend side to return proper status header code
Check if response valid in successCallback
if (response.data.exception) {
window.location.href = "/ATS/500";
}
NOTE: but basically it's wrong that server return this type or error with stacktrace.
Exceptions handling examples
I'm working on a button that calls an action in my asp.net mvc controller. I'm trying to catch errors and display them to the user in a decent way, but I can't seem to figure out how to do this properly. Whenever I force an exception (for testing purposes) in my controller, the .sucess part of my ajax call i still fired. Here's my ajax call:
$(document).ready(function() {
$("#del").on("click", function() {
var message;
$.ajax({
url: "#Url.Action("DeleteImage", "UnitSummary")",
type: "GET",
dataType: "json",
data: { unitId: "#Model.UnitId" },
error: function(msg) {
message = msg;
$('#delsection').hide().html('<div class="alert alert-danger"><strong>Ouch!</strong> ' + message.statusText + '</div>').fadeIn('slow');
},
success: function(msg) {
message = msg;
$('#delsection').hide().html('<div class="alert alert-success"><strong>Success!</strong> Image was deleted.</div>').fadeIn('slow');
}
});
});
And here's my controller:
[HttpGet]
public ActionResult DeleteImage(int unitId)
{
try
{
throw new Exception("Forced error");
UnitClient.UpdateUnitImage(unitId, new byte[0]);
}
catch (Exception e)
{
Log.Error(e);
return Json(new { e.Message }, JsonRequestBehavior.AllowGet);
}
return Json(new JsonResult(), JsonRequestBehavior.AllowGet);
}
Sucess always gets called, even though the image is not deleted. What am I missing here?
Whenever I force an exception (for testing purposes) in my controller,
the .sucess part of my ajax call i still fired.
The following line of code is not an exception that jQuery's ajax interprets as an error response from the server (hence no call to the error callback), but a regular 200 OK response:
return Json(new { e.Message }, JsonRequestBehavior.AllowGet);
Do it like this instead:
return new HttpStatusCodeResult(HttpStatusCode.BadRequest, e.Message);
This is where HTTP status codes come into play, BadRequest is an HTTP error status code.
Here's more about BadRequest:
Equivalent to HTTP status 400. BadRequest indicates that the request
could not be understood by the server. BadRequest is sent when no
other error is applicable, or if the exact error is unknown or does
not have its own error code.