Unauthorized AJAX request succeeds - asp.net-mvc-3

I have following controller method:
[HttpPost]
[Authorize(Roles="some_role_actual_user_is_NOT_in")
public ActionResult AJAXMethod()
{
return Json(new { message = "server message");
}
and page with script:
function sendReq()
{
$.ajax({
type: "POST",
data: { somedata: "somedata" },
url: "/Path/To/AJAXMethod",
success: onAJAXSuccess,
error: onAJAXError
});
}
function onAJAXSuccess(response, status, xhr)
{
alert("success: " + response.message);
alert(status);
}
function onAJAXError(xhr,status,error)
{
alert("error: " + status);
alert(error);
}
When I call sendReq with user not in the authorized role the AJAX call still suceed - callback onAJAXSuccess is called, but response.message is undefined.

This is correct behaviour. The success of an AJAX call is only determined by the fact the the server responded with a 200 OK. You will need to interrogate the returned response yourself to ensure it is in the format you expect.
For example:
if (typeof response.message != "undefined" && response.message != "") {
// it worked
}
else {
// didn't work || user did not have access.
}

Related

how to send serialized form to webapi Method

im trying to send my from with ajax( $.post ) to a webApi . ajax request run succesfull but when i send data to method in web api form collection get null then my method return "false"
please help me
My WebApi Method
[System.Web.Http.HttpPost]
public string AddRecord([FromBody]FormCollection form)
{
try
{
PersonBLL personbll = new PersonBLL();
var person = new tbl_persons();
person.firstname = form["txt_namePartial"];
person.lastname = form["txt_lastnamePartial"];
person.age = byte.Parse(form["txt_agePartial"]);
var result = personbll.AddRecord(person);
return result;
}
catch (Exception)
{
return "false";
}
}
my Ajax function
function AddRecordWithFormCollection(url, callback) {
$.post("/api/Person/AddRecord",JSON.stringify(url) , function (data, status) {
if (status == "success") {
hidePreloader();
unloadDiv("div_operation");
BindTable();
//AddRowTable(data, obj.name, obj.lastname, obj.age);
return callback(data);
} else {
alert("Error in Method [AddRecord]");
hidePreloader();
}
});
}
I often use that :
var form = $("#body").find("form").serialize();
$.ajax({
type: 'POST'
url: "/api/Person/AddRecord",
data: form,
dataType: 'json',
success: function (data) {
// Do something
},
error: function (data) {
// Do something
}
});
Get a try because I never used the FormCollection object type but just a model class.
This should be:
url=$("#form").serialize();
function AddRecordWithFormCollection(url, callback) {
$.post("/api/Person/AddRecord",url , function (data, status) {
if (status == "success") {
hidePreloader();
unloadDiv("div_operation");
BindTable();
//AddRowTable(data, obj.name, obj.lastname, obj.age);
return callback(data);
} else {
alert("Error in Method [AddRecord]");
hidePreloader();
}
});
}

Routing through AJAX

I have an ajax request handling validation of form fields (login+signup+forget password). In its success scenario, I want it to route to another page, but when I use Redirect::route('name'); as return from controller, it completes the request with 200 and generates another GET request which just returns the html as response and does not route to other page.
AJAX
$('form[data-remote]').on('submit', function (e) {
var form = $(this);
var method = form.find('input[name="_method"]').val() || 'POST';
var url = form.prop('action');
$.ajax({
type: method,
url: url,
data: form.serialize(),
beforeSend: function () {
$('#ajax-loading').show();
$(".has-error").text("");
$('#login-error').addClass('display-hide');
$('#forget-user-error').addClass('display-hide');
}
})
.done(function (data) {
if (data.signup_fail) {
$.each(data.errors, function (index, value) {
var errorSpan = '#' + index + '_error';
$(errorSpan).removeClass('hidden');
$(errorSpan).empty().append(value);
});
$('#successMessage').empty();
}
else if (data.email_fail) {
$('#email_error').text('This Email already in use against an account.');
}
else if (data.company_fail) {
$('#email-error-popup').trigger('click');
}
else if (data.login_fail) {
$('#login-error').removeClass('display-hide');
}
else if (data.forget_fail) {
$.each(data.errors, function (index, value) {
var errorSpan = '#' + index + '_error';
$(errorSpan).empty().append(value);
});
$('#successMessage').empty();
}
else if (data.forget_user_fail) {
$('#forget-user-error').removeClass('display-hide');
}
else if (data.reset_fail) {
$.each(data.errors, function (index, value) {
var errorSpan = '#' + index + '_error';
$(errorSpan).removeClass('hidden');
$(errorSpan).empty().append(value);
});
$('#successMessage').empty();
}
})
.fail(function (jqXHR, ajaxOptions, thrownError) {
alert('No response from server');
});
return false;
});
How can I route to the other page on success condition? The ajax is triggered on a form submit button.
As you are doing an ajax request you can't just redirect from the controller on successful validation. Instead, just return the url you want to redirect to, as response to the ajax request similar to the way you are returning the validation errors. And in your js file use that url to redirect to new page.
#your above code
else if (data.forget_user_fail) {
$('#forget-user-error').removeClass('display-hide');
}
else if (data.reset_fail) {
$.each(data.errors, function (index, value) {
var errorSpan = '#' + index + '_error';
$(errorSpan).removeClass('hidden');
$(errorSpan).empty().append(value);
});
$('#successMessage').empty();
}
else{
window.location.replace(data.redirect_url); //this will redirect to new page
}
})
.fail(function (jqXHR, ajaxOptions, thrownError) {
alert('No response from server');
});
return false;
});

MVC3 ajax action request: handling answer

I'm doing an Ajax request to an MVC3 action and I want to process the JsonResult in the success or error function.
Currently the behaviour is strange: Before hitting my breakpoint in the action it hits the error function.
Can anyone help me please and has a hint?
My view:
<form id="myForm">
//fields go here...
<button id="myButton" onclick="myFunction();">ButtonName</button>
</form>
The ajax call:
function myFunction() {
if ($('#myForm').valid() == false) {
return;
}
var data = {
val1: $("#val1").val(),
val2: $("#val2").val()
};
var url = "/Controller/Action";
$.ajax({
url: url,
type: 'POST',
dataType: 'json',
cache: false,
data: data,
success: function (data, statusCode, xhr) {
alert('1');
if (data && data.Message) {
alert(data.Message);
alert('2');
}
alert('3');
},
error: function (xhr, errorType, exception) {
alert('4');
var errorMessage = exception || xhr.statusText;
alert("There was an error: " + errorMessage);
}
});
return false;
}
My action:
[HttpPost]
public ActionResult Action(Class objectName)
{
var response = new AjaxResponseViewModel();
try
{
var success = DoSomething(objectName);
if (success)
{
response.Success = true;
response.Message = "Successful!";
}
else
{
response.Message = "Error!";
}
}
catch (Exception exception)
{
response.Success = false;
response.Message = exception.Message;
}
return Json(response);
}
If you look in the ajax call I get directly the alert #4 and only then the action gets called which is too late. Unfortunately the exception is null. Directly after that the view gets closed.
You are not preventing the default onclick behavior. Can you try the following instead?
onclick="return myFunction()"

Can I return custom error from JsonResult to jQuery ajax error method?

How can I pass custom error information from an ASP.NET MVC3 JsonResult method to the error (or success or complete, if need be) function of jQuery.ajax()? Ideally I'd like to be able to:
Still throw the error on the server (this is used for logging)
Retrieve custom information about the error on the client
Here is a basic version of my code:
Controller JsonResult method
public JsonResult DoStuff(string argString)
{
string errorInfo = "";
try
{
DoOtherStuff(argString);
}
catch(Exception e)
{
errorInfo = "Failed to call DoOtherStuff()";
//Edit HTTP Response here to include 'errorInfo' ?
throw e;
}
return Json(true);
}
JavaScript
$.ajax({
type: "POST",
url: "../MyController/DoStuff",
data: {argString: "arg string"},
dataType: "json",
traditional: true,
success: function(data, statusCode, xhr){
if (data === true)
//Success handling
else
//Error handling here? But error still needs to be thrown on server...
},
error: function(xhr, errorType, exception) {
//Here 'exception' is 'Internal Server Error'
//Haven't had luck editing the Response on the server to pass something here
}
});
Things I've tried (that didn't work out):
Returning error info from catch block
This works, but the exception can't be thrown
Editing HTTP response in catch block
Then inspected xhr in the jQuery error handler
xhr.getResponseHeader(), etc. contained the default ASP.NET error page, but none of my information
I think this may be possible, but I just did it wrong?
You could write a custom error filter:
public class JsonExceptionFilterAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.StatusCode = 500;
filterContext.ExceptionHandled = true;
filterContext.Result = new JsonResult
{
Data = new
{
// obviously here you could include whatever information you want about the exception
// for example if you have some custom exceptions you could test
// the type of the actual exception and extract additional data
// For the sake of simplicity let's suppose that we want to
// send only the exception message to the client
errorMessage = filterContext.Exception.Message
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
}
and then register it either as a global filter or only apply to particular controllers/actions that you intend to invoke with AJAX.
And on the client:
$.ajax({
type: "POST",
url: "#Url.Action("DoStuff", "My")",
data: { argString: "arg string" },
dataType: "json",
traditional: true,
success: function(data) {
//Success handling
},
error: function(xhr) {
try {
// a try/catch is recommended as the error handler
// could occur in many events and there might not be
// a JSON response from the server
var json = $.parseJSON(xhr.responseText);
alert(json.errorMessage);
} catch(e) {
alert('something bad happened');
}
}
});
Obviously you could be quickly bored to write repetitive error handling code for each AJAX request so it would be better to write it once for all AJAX requests on your page:
$(document).ajaxError(function (evt, xhr) {
try {
var json = $.parseJSON(xhr.responseText);
alert(json.errorMessage);
} catch (e) {
alert('something bad happened');
}
});
and then:
$.ajax({
type: "POST",
url: "#Url.Action("DoStuff", "My")",
data: { argString: "arg string" },
dataType: "json",
traditional: true,
success: function(data) {
//Success handling
}
});
Another possibility is to adapt a global exception handler I presented so that inside the ErrorController you check if it was an AJAX request and simply return the exception details as JSON.
The advice above wouldn't work on IIS for remote clients. They will receive a standard error page like 500.htm instead of a response with a message.
You have to use customError mode in web.config, or add
<system.webServer>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
or
"You can also go into IIS manager --> Error Pages then click on the
right on "Edit feature settings..." And set the option to "Detailed
errors" then it will be your application that process the error and
not IIS."
you can return JsonResult with error and track the status at javascript side to show error message :
JsonResult jsonOutput = null;
try
{
// do Stuff
}
catch
{
jsonOutput = Json(
new
{
reply = new
{
status = "Failed",
message = "Custom message "
}
});
}
return jsonOutput ;
My MVC project wasn't returning any error message (custom or otherwise).
I found that this worked well for me:
$.ajax({
url: '/SomePath/Create',
data: JSON.stringify(salesmain),
type: 'POST',
contentType: 'application/json;',
dataType: 'json',
success: function (result) {
alert("start JSON");
if (result.Success == "1") {
window.location.href = "/SomePath/index";
}
else {
alert(result.ex);
}
alert("end JSON");
},
error: function (xhr) {
alert(xhr.responseText);
}
//error: AjaxFailed
});
Showing the xhr.responseText resulted in a very detailed HTML formatted alert message.
If for some reason you can't send a server error. Here's an option that you can do.
server side
var items = Newtonsoft.Json.JsonConvert.DeserializeObject<SubCat>(data); // Returning a parse object or complete object
if (!String.IsNullOrEmpty(items.OldName))
{
DataTable update = Access.update_SubCategories_ByBrand_andCategory_andLikeSubCategories_BY_PRODUCTNAME(items.OldName, items.Name, items.Description);
if(update.Rows.Count > 0)
{
List<errors> errors_ = new List<errors>();
errors_.Add(new errors(update.Rows[0]["ErrorMessage"].ToString(), "Duplicate Field", true));
return Newtonsoft.Json.JsonConvert.SerializeObject(errors_[0]); // returning a stringify object which equals a string | noncomplete object
}
}
return items;
client side
$.ajax({
method: 'POST',
url: `legacy.aspx/${place}`,
contentType: 'application/json',
data: JSON.stringify({data_}),
headers: {
'Accept': 'application/json, text/plain, *',
'Content-type': 'application/json',
'dataType': 'json'
},
success: function (data) {
if (typeof data.d === 'object') { //If data returns an object then its a success
const Toast = Swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000
})
Toast.fire({
type: 'success',
title: 'Information Saved Successfully'
})
editChange(place, data.d, data_);
} else { // If data returns a stringify object or string then it failed and run error
var myData = JSON.parse(data.d);
Swal.fire({
type: 'error',
title: 'Oops...',
text: 'Something went wrong!',
footer: `<a href='javascript:showError("${myData.errorMessage}", "${myData.type}", ${data_})'>Why do I have this issue?</a>`
})
}
},
error: function (error) { console.log("FAIL....================="); }
});

optional $.ajax call

I have html.actionlink in my asp.net MVC 3view and jquery ajax call on link click. In my action method suppose I have this:
if (a == 2) //return ok
return Json(new { Error = "false", Message = "Everything ok" }, JsonRequestBehavior.AllowGet);
else
return Content("");
Ajax call is:
$(function () {
$('#checkExists').click(function () {
$.ajax({
url: $('#checkExists').attr('href'),
global: true,
type: 'GET',
timeout: 5000,
success: function (data) { //invoke when receive response from server
if (data != null && data.Error != '') //return failed
{
alert(data.Error);
}
// else {
// alert('error occurs 1');
// //action ok here
// }
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr + ajaxOptions + "Cannot connect to server to load data"); //sever is not available
},
complete: function () { //ajax done
//alert('complete');
}
});
return false;
});
In case of else , ajax i called, how can I stop $.ajax call ?
you have already made the ajax call there is no way you can undo it in your current scenario
what you can do is send a doNothing response
if (a == 2) //return ok
return Json(new { Error = "false", Message = "Everything ok" }, JsonRequestBehavior.AllowGet);
else
return Json(new { Message = "do nothing" }, JsonRequestBehavior.AllowGet);
and in the ajax success callback
success:function(data){
if(data.Message==='do nothing'){
// simply do nothing
}
}
jsut as a side note you can cancel the ajax call before you have instantiated it see this SO answer Abort Ajax requests using jQuery
update
if (a == 2) //return ok
return Json(new { Error = "false", Message = "Everything ok" }, JsonRequestBehavior.AllowGet);
else
return Content("");
and in the success callback
success:function(data){
if(!data.Message)
//alert(data); //content will be shown
}
What do you mean by stop the AJAX call? You already sent the AJAX call and it hit the controller action. It is this controller action that returned a JSON or a plain text. But at this stage it is too late to stop something that was already done. It's ike trying to bring someone back from death.

Resources