I have a project in MVC4 with C#. In this project, one of my controllers has a method to be called by an Ajax function:
[HttpPost]
public string EditPackage(int id, string newPkgName)
{
try{
//do logic here
return "OK";
}catch(Exception exc){
return "An error occurred, please try later! " + exc.Message;
}
}
This method is called by the following Ajax functions, using jQuery:
$.ajax({
url: $(this).data('url'),
type: 'POST',
contentType: 'application/json; charset=utf-8',
traditional: true,
data: JSON.stringify({ id: id, newPkgName: newPkgName}),
success: function () {
location.reload(true);
successNotification("Package edited successfuly!");
},
error: function (message) {
errorNotification(message);
}
});
The problem with this code, is that even if the server returns the return "An error occurred, please try later! " + exc.Message; message in the catch, the success function is the one always called.
In order words, I never run the error function no matter what I do.
To fix this I checked the official documentation:
http://api.jquery.com/jQuery.ajax/
However, since I am failry new to this I can't understand any of the parameters, nor how to use them effectively.
How can I create a good error message with all the possible information using Ajax, jQuery and my controller?
The error part of the $.ajax call only fires if the returned status code is anything other than 200 OK. In your case you are returning a plaintext response which will therefore be 200. You can change this behaviour like this:
try {
// do logic here
return "OK";
}
catch (Exception exc) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "Bad Request");
}
error: function (jqXHR, textStatus, errorThrown) {
errorNotification(textStatus);
}
You can change the HttpStatusCode to whatever suits your need.
Alternatively, you can keep the 200 response and return JSON with a flag to indicate whether or not the request was successful:
[HttpPost]
public ActionResult EditPackage(int id, string newPkgName)
{
try {
//do logic here
return Json(new { Success = true, Message = "OK"});
}
catch (Exception exc) {
return Json(new { Success = false, Message = "An error occurred, please try later! " + exc.Message });
}
}
Then you can remove the error handler, and check the state of the flag in your success handler:
success: function(response) {
if (response.Success) {
location.reload(true);
successNotification("Package edited successfuly!");
}
else {
errorNotification(response.Message);
}
},
I do the following, it might not be the best approach but it works for what I try to do.
[HttpPost]
public ActionResult EditPackage(int id, string newPkgName)
{
try{
//do logic here
return Json(new {Success = true, Message = "OK"});
}catch(Exception exc){
return Json(new {Success = false, Message = "An error occurred, please try later! " + exc.Message});
}
}
Then my Ajax looks as follows:
$.ajax({
url: $(this).data('url'),
type: 'POST',
contentType: 'application/json; charset=utf-8',
traditional: true,
data: JSON.stringify({ id: id, newPkgName: newPkgName}),
success: function (data) {
if(data.Success)
{
location.reload(true);
successNotification("Package edited successfuly!");
}
else
{
errorNotification(data.Message);
}
},
error: function (message) {
errorNotification(message);
}
});
I do this so that you have the standard error catching http errors from the server, but it means you can pass a success or failure back in a way that is more useful. It also means that if your update fails for a validation reason or something you can pass that message back nicely.
Related
I would like to call a code behind function from the client side.
The function cannot be static - should modified unstatic variabels.
I was able to create a non-visible button, and when I need that function I demonstrate a click on that btn.
How can I send parameters to that code behind function?
$.ajax({
url: '/ControllerName/ActionName',
type: "GET",
data: { param1: val1 },
success: function (res) {
alert(res) // res is results that came from function
}
});
This is the client side to call backend method. The server side to accept this request:
public ActionResult ActionName(string param1)
{
return View(param1);
}
In this case, we used jQuery, the javascript plugin, and we used AJAX request, also sending parameters.
Using MVC and jQuery
Client Side ( Using Razor )
$.ajax({
url: '#Url.Action("ActionName","ControllerName",new{parameters})',
type: "GET",
contentType: "application/json",
data: { param1: val1 },
success: function (res) {
alert(res) // res is results that came from function
},
error: function (jqXHR, error, errorThrown) {
console.log('An error as occured');
},
});
Server Side
[HttpGet]
public JsonResult ActionName(string param1)
{
return Json(param1, JsonRequestBehavior.AllowGet);
}
Note: HttpGet Verb is the default verb for every ActionResult/JsonResult
the button have a CommandArgument attribute that you can use to send a value to that function and you can read it as follow :
public void yourFunction(object sender,Eventargs e)
{
string args = ((LinkButton)sender).CommandArgument.ToString();
// rest of code here
}
I got some problem while posting JSON data into MVC 4 controller.
Below method is working fine in Firefox but unfortunately failed in IE 9
The JavaScript :
var newCustomer = {
CustName: $("#CustName").val(),
CustLocalName: $("#CustLocalName").val(),
CustNumber: $("#CustNumber").val(),
CountryID: $("#SelectCountry").val(),
City: $("#City").val()
};
$.ajax({
url: '#Url.Content("~/CustomerHeader/CreateCustomerHeader")',
cache: false,
type: "POST",
dataType: "json",
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(newCustomer),
success: function (mydata) {
$("#message").html("Success");
},
error: function () {
$("#message").html("Save failed");
}
});
and this is my controller :
public JsonResult CreateCustomerHeader(CustomerHeader record)
{
try
{
if (!ModelState.IsValid)
{
return Json(new { Result = "ERROR", Message = "Form is not valid! Please correct it and try again." });
}
RepositoryHeader.Update(record);
return Json(new { Result = "OK", Record = record});
}
catch (Exception ex)
{
return Json(new { Result = "ERROR", Message = ex.Message });
}
}
the "data" variable as in public JsonResult CreateCustomerHeader(CustomerHeader **data**) is getting NULL but while using FireFox it holds the correct value.
UPDATE : New method trying using $.post
function CreateNewCustomer(newCustomer) {
$.post("/CustomerHeader/CreateCustomerHeader",
newCustomer,
function (response, status, jqxhr) {
console.log(response.toString())
});
}
Based off the bit that you've shown, this is a simplified variation that may work more consistently, using jQuery.post() (http://api.jquery.com/jQuery.post/):
var data = {
CustName: $("#CustName").val(),
CustLocalName: $("#CustLocalName").val(),
CustNumber: $("#CustNumber").val(),
CountryID: $("#SelectCountry").val(),
City: $("#City").val()
};
$.post({
'#Url.Action("CreateCustomerHeader", "CustomerHeader")',
data,
function(response, status, jqxhr){
// do something with the response data
}).success(function () {
$("#message").html("Success");
}).error(function () {
$("#message").html("Save failed");
});
$.post() uses $.ajax as it's base, but abstracts some of the details away. For instance, $.post calls are not cached, so you don't need to set the cache state (and setting it is ignored if you do). Using a simple JavaScript object lets jQuery decide how to serialize the POST variables; when using this format, I rarely have issues with the model binder not being able to properly bind to my .NET classes.
response is whatever you send back from the controller; in your case, a JSON object. status is a simple text value like success or error, and jqxhr is a jQuery XMLHttpRequest object, which you could use to get some more information about the request, but I rarely find a need for it.
first of all I would like to apologize #Tieson.T for not providing details on JavaScript section of the view. The problem is actually caused by $('#addCustomerHeaderModal').modal('hide') that occurred just after ajax call.
The full script :
try{ ..
var newCustomer =
{
CustName: $("#CustName").val(),
CustLocalName: $("#CustLocalName").val(),
CustNumber: $("#CustNumber").val(),
CountryID: $("#SelectCountry").val(),
City: $("#City").val()
};
$.ajax({
url: '/CustomerHeader/CreateCustomerHeader',
cache: false,
type: "POST",
dataType: "json",
data: JSON.stringify(newCustomer),
contentType: "application/json; charset=utf-8",
success: function (mydata) {
$("#message").html("Success");
},
error: function () {
$("#message").html("Save failed");
}
});
}
catch(Error) {
console.log(Error.toString());
}
//$('#addCustomerHeaderModal').modal('hide')//THIS is the part that causing controller cannot retrieve the data but happened only with IE!
I have commented $('#addCustomerHeaderModal').modal('hide') and now the value received by controller is no more NULL with IE. Don't know why modal-hide event behave like this with IE9.
Thanks for all the efforts in solving my problem guys :-)
I am trying to POST some data to my ASP.Net MVC Web API controller and trying to get it back in the response. I have the following script for the post:
$('#recordUser').click(function () {
$.ajax({
type: 'POST',
url: 'api/RecordUser',
data: $("#recordUserForm").serialize(),
dataType: 'json',
success: function (useremail) {
console.log(useremail);
},
error: function (xhr, status, err) {
},
complete: function (xhr, status) {
if (status === 'error' || !xhr.responseText) {
alert("Error");
}
else {
var data = xhr.responseText;
alert(data);
//...
}
}
});
});
The problem with this script is that whenever I try to post the data, the jQuery comes back in "error" instead of "success".
I have made sure that there is no problem with my controller. I can get into my api method in debug mode whenever the request is made and can see that it is getting the data from the POST request and is returning it back. This controller is quite simple:
public class RecordUserController : ApiController
{
public RecordUserEmailDTO Post(RecordUserEmailDTO userEmail)
{
return userEmail;
}
}
I am not sure how I can get jQuery to print out any useful error messages. Currently when I try to debug the jQuery code using Chrome console it shows an empty xhr.responseText, nothing in "err" object and "status" set to "error" which as you see is not quite helpful.
One more thing that I have tried is to run the following code directly from the console:
$.ajax({
type: 'POST',
url: 'api/RecordUser',
data: {"Email":"email#address.com"},
dataType: 'json',
success: function (useremail) {
console.log(useremail);
},
error: function (xhr, status, err) {
console.log(xhr);
console.log(err);
console.log(status);
alert(err.Message);
},
complete: function (xhr, status) {
if (status === 'error' || !xhr.responseText) {
alert("Error");
}
else {
var data = xhr.responseText;
alert(data);
}
}
});
i.e. using the same script without actually clicking on the button and submitting the form. Surprisingly, this comes back with the right response and I can see my data printed out in console. For me this atleast means that my Web API controller is working fine but leaves me with no clue as to why it is not working on clicking the button or submitting the form and goes into "error" instead of "success".
I have failed to find any errors in my approach and would be glad if someone could help me in getting a response back when the form is posted.
As suggested by Alnitak, I was using complete callback along with success and error ones. Removing complete from my code fixed the issue.
Thanks to Alnitak.
I needs to show the Json returned message.
In the controller, an exception is thrown and caught in a catch block. I am returning the fault error message.
In Ajax, the success part always executes. But if it is an error from my webservice, I don't want to execute the normal; instead I want to show an error message.
How I can achieve this?
My code below:
Controller
[HttpPost]
public JsonResult DeleteClientRecord()
{
bool result = true;
try
{
result = ClientCRUDCollection.DeleteClient(deleteClientId);
}
catch (Exception ex)
{
return Json(ex.Message, JsonRequestBehavior.AllowGet);
}
return Json(new { result }, JsonRequestBehavior.AllowGet);
}
AJAX Call
$("#YesDelete").click(function () {
$.ajax({
type: "POST",
async: false,
url: "/Client/DeleteClientRecord",
dataType: "json",
error: function (request) {
alert(request.responseText);
event.preventDefault();
},
success: function (result) {
// if error from webservice I want to differentiate here somehow
$("#Update_" + id).parents("tr").remove();
$('#myClientDeleteContainer').dialog('close');
return false;
}
});
});
Please can anyone help me on this.
[HttpPost]
public JsonResult DeleteClientRecord()
{
bool result = true;
try
{
result = ClientCRUDCollection.DeleteClient(deleteClientId);
}
catch (Exception ex)
{
return Json(new { Success="False", responseText=ex.Message});
}
return Json(new { result }, JsonRequestBehavior.AllowGet);
}
to show error message, you should add error scope after success scope in AJAX call like this:
$("#YesDelete").click(function () {
$.ajax({
type: "POST",
async: false,
url: "/Client/DeleteClientRecord",
dataType: "json",
error: function (request) {
alert(request.responseText);
event.preventDefault();
},
success: function (result) {
// if error from webservice I want to differentiate here somehow
$("#Update_" + id).parents("tr").remove();
$('#myClientDeleteContainer').dialog('close');
return false;
}
error: function (xhr) {alert(JSON.parse(xhr.responseText).Message); }
});
});
add Response.StatusCode to the response
_httpContextAccessor.HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
I'm using ASP.Net MVC, but this applies to any framework.
I'm making an Ajax call to my server, which most of the time returns plain old HTML, however if there is an error, I'd like it to return a JSON object with a status message (and a few other things). There doesn't appear to be a way for the dataType option in the jQuery call to handle this well. By default it seems to parse everything as html, leading to a <div> being populated with "{ status: 'error', message: 'something bad happened'}".
[Edit] Ignoring the dataType object and letting jQuery figure out doesn't work either. It views the type of the result as a string and treats it as HTML.
One solution I came up with is to attempt to parse the result object as JSON. If that works we know it's a JSON object. If it throws an exception, it's HTML:
$.ajax({
data: {},
success: function(data, textStatus) {
try {
var errorObj = JSON.parse(data);
handleError(errorObj);
} catch(ex) {
$('#results').html(data);
}
},
dataType: 'html', // sometimes it is 'json' :-/
url: '/home/AjaxTest',
type: 'POST'
});
However, using an Exception in that way strikes me as pretty bad design (and unintuitive to say the least). Is there a better way? I thought of wrapping the entire response in a JSON object, but in this circumstance, I don't think that's an option.
Here's the solution that I got from Steve Willcock:
// ASP.NET MVC Action:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AjaxTest(int magic) {
try {
var someVal = GetValue();
return PartialView("DataPage", someVal);
} catch (Exception ex) {
this.HttpContext.Response.StatusCode = 500;
return Json(new { status = "Error", message = ex.Message });
}
}
// jQuery call:
$.ajax({
data: {},
success: function(data, textStatus) {
$('#results').html(data);
},
error: function() {
var errorObj = JSON.parse(XMLHttpRequest.responseText);
handleError(errorObj);
},
dataType: 'html',
url: '/home/AjaxTest',
type: 'POST'
});
For your JSON errors you could return a 500 status code from the server rather than a 200. Then the jquery client code can use the error: handler on the $.ajax function for error handling. On a 500 response you can parse the JSON error object from the responseText, on a 200 response you can just bung your HTML in a div as normal.
While Steve's idea is a good one, I'm adding this in for completeness.
It appears that if you specify a dataType of json but return HTML, jQuery handles it fine.
I tested this theory with the following code:
if($_GET['type'] == 'json') {
header('Content-type: application/json');
print '{"test":"hi"}';
exit;
} else {
header('Content-type: text/html');
print '<html><body><b>Test</b></body></html>';
exit;
}
The $_GET['type'] is just so I can control what to return while testing. In your situation you'd return one or the other depending on whether things went right or wrong. Past that, with this jQuery code:
$.ajax({
url: 'php.php?type=html', // return HTML in this test
dataType: 'json',
success: function(d) {
console.log(typeof d); // 'xml'
}
});
Even though we specified JSON as the dataType, jQuery (1.3.2) figures out that its not that.
$.ajax({
url: 'php.php?type=json',
dataType: 'json',
success: function(d) {
console.log(typeof d); // 'object'
}
});
So you could take advantage of this (as far as I know) undocumented behavior to do what you want.
But why not return only JSON regardless of the status (success or error) on the POST and the use a GET to display the results? It seems like a better approach if you ask me.
Or you could always return a JSON response, and have one parameter as the HTML content.
Something like:
{
"success" : true,
"errormessage" : "",
"html" : "<div>blah</div>",
}
I think you'd only have to escape double quotes in the html value, and the json parser would undo that for you.
I ran into this exact same issue with MVC/Ajax/JQuery and wanting to use multiple dataTypes (JSON and HTML). I have a AJAX request to uses an HTML dataType to return the data, but I attempt convert the data that comes back from the ajax request to a JSON object. I have a function like this that I call from my success callback:
_tryParseJson: function (data) {
var jsonObject;
try {
jsonObject = jQuery.parseJSON(data);
}
catch (err) {
}
return jsonObject;
}
I then assume that if the jsonObject and errorMessage property exist, that an error occured, otherwise an error did not occur.
I accomplished this by using the ajax success and error callbacks only. This way I can have mixed strings and json objects responses from the server.
Below I'm prepared to accept json, but if I get a status of "parsererror" (meaning jquery couldn't parse the incoming code as json since that's what I was expecting), but it got a request status of "OK" (200), then I handle the response as a string. Any thing other than a "parsererror" and "OK", I handle as an error.
$.ajax({
dataType: 'json',
url: '/ajax/test',
success: function (resp) {
// your response json object, see if status was set to error
if (resp.status == 'error') {
// log the detail error for the dev, and show the user a fail
console.log(resp);
$('#results').html('error occurred');
}
// you could handle other cases here
// or use a switch statement on the status value
},
error: function(request, status, error) {
// if json parse error and a 200 response, we expect this is our string
if(status == "parsererror" && request.statusText == "OK") {
$('#results').html(request.responseText);
} else {
// again an error, but now more detailed and not a parser error
// and we'll log for dev and show the user a fail
console.log(status + ": " + error.message);
$('#results').html('error occurred');
}
}
});