Unexpected GET request after POST on AJAX call to MVC Action - ajax

I have an action method that is invoked with POST method over AJAX. Method looks like this:
[HttpPost]
public ActionResult Save(MyModel model)
{
/// do something and save
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
What happens is that after this method is call by the $.ajax, from unknown reason follow up GET request is made to same controller and same action. This call is not made anywhere and it's probably implemented either in browser or in ASP.NET MVC as Post/Redirect/Get pattern which I don't need in this case.
Is there a way to disable this programmatically because GET counterpart of Save method is not implemented and server returns 404 with HTML contents in it.
EDIT, this is the client-side AJAX script:
function saveDonkey(donkey) {
var jsonData = JSON.stringify(donkey);
$.ajax({
url: "/Donkey/Save",
data: jsonData,
contentType: "application/json",
dataType: "json",
type: "POST",
success: function () {
fetchPage(); /// This just issues GET request to another predefined method
}
});
}

Related

Why is this basic ajax call giving me a 400 and not firing to the controller?

This is only a problem for me in my newest dot net core 2 web app, it works in previous dot net apps with no issue.
I have a custom javascript file with paths to various servers that my site is hosted on(mainly dev, test, live).
My ajax call looks like the following:
var gameid = '#Html.Raw(Model.Id)';
$.ajax({
type: 'GET',
url: url() + "UserGames/HasGame?id=" +gameid,
cache: false,
success: function (data) {
console.log(data);
},
error: function (req, status, err) {
console.log('Something went wrong', status, err);
}
});
The url() in question is simply looking at my local server while testing(*please note, this port has been edited, it is correct):
function url() {
return "https://localhost:4432/";
}
The error is not firing as it isnt even reaching the controller function being used.
I'm absolutely bemused as to why this isnt working, i could understand if i was getting some sort of error back, but i have used ajax calls in all of my apps and not had this problem at all until using core 2.
Has anything changed that may have affected the way you use ajax calls?
Method that is trying to fire, but i mentioned, it isnt hitting the controller(NOTE: the method does have code in it, it just isnt hitting the controller in the first place)
[HttpGet]
[ValidateAntiForgeryToken]
public async Task<IActionResult> HasGame(int id)
{
//stuff in here
}
You are getting a 400 (Bad Request) response because the framework expects the RequestVerificationToken as part of the request.The framework uses this to prevent possible CSRF attacks. If your request does not have this information, the framework will return the 400 bad request. Your current code is not sending it.
You can fix it by explicitly send that RequestVerificationToken
The form tag helper automatically creates a hidden input with name atttribute value __RequestVerificationToken and stores the token as the value of the hidden input.
var token = $("[name='__RequestVerificationToken']").val();
var gameid = '#Html.Raw(Model.Id)';
$.ajax({
type: 'GET',
url: url() + "UserGames/HasGame?id=" +gameid,
headers:{ "RequestVerificationToken": token },
success: function (data) {
console.log(data);
},
error: function (req, status, err) {
console.log('Something went wrong', status, err);
}
});
In the above example, we are using some jQuery code to get the input element with name __RequestVerificationToken and reading the value of it. A more robust approach would be injecting the IAntiforgery implementation to the view and using the GetAndStoreTokens method.
We will be injecting IHttpContextAccessor to the view. So make sure it is wired up with DI properly. Add this line to your Startup classes' ConfigureServices method.
services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();
Now in your view, you can inject IHttpContextAccessor and IAntiforgery and then call the GetAndStoreTokens to get the token. Here i wrapped that into a helper function.
#inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContext
#inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
#functions{
public string GetAntiXsrfRequestToken()
{
return Xsrf.GetAndStoreTokens(HttpContext.HttpContext).RequestToken;
}
}
Now later in my js, i can call this method inside my javascript code instead of using jQuery to get the input value.
var token = "#GetAntiXsrfRequestToken()";
var gameid = '#Html.Raw(Model.Id)';
$.ajax({
type: 'GET',
url: url() + "UserGames/HasGame?id=" +gameid,
headers:{ "RequestVerificationToken": token },
success: function (data) {
console.log(data);
},
error: function (req, status, err) {
console.log('Something went wrong', status, err);
}
});
Or Simply remove [ValidateAntiForgeryToken] attribute decoration from the action method, which excludes this check.
I recommend you to take advantage of the[ValidateAntiForgeryToken] method. Send the token as part of your request(first approach)
If anyone else comes across this issue, i managed to fix it by doing the following to both the call and the controller:
type: 'GET',
url: '#Url.Action("HasGame", "UserGames")',
data: {id : gameid},
And the controller in core 2 does not seem to like you declaring [HttpGet] at all, so i removed that also.
Thanks for all the help provided.

Ajax Routing Calling Controller Name Twice

I am trying to do a simple call to my controller via ajax. The RouteConfig has not been changed and set to the default values. When I make ajax call, the Url that is requested in the "Network" debugging tools is:
'http://localhost:59275/Leaderboard/Leaderboard/GetPosition'
This is causing a 404 because the Controller, Leaderboard, is being added into the Url twice. The correct url should be
'http://localhost:59275/Leaderboard/GetPosition'
My ajax call is as follows:
$.ajax({
url: 'Leaderboard/GetPosition',
type: "GET",
dataType: 'xml',
success: function (data) {
$('#results').html(data);;
}
});
and my controller is as follows:
public class LeaderboardController : Controller
{
[Webmethod]
public static DataTable GetPosition()
{
// do stuff
}
}
If the root URL of the page that request the ajax is "Leaderboard" then the url on the ajax call should only "GetPosition"
Or you can use "/Leaderboard/GetPosition" with "/" in front
Use Url.Action helper for generating correct url.
Change this:
url: 'Leaderboard/GetPosition'
to this:
url: '#Url.Action("GetPosition","Leaderboard")'

Antiforgery token and object parameter do not post to MVC4 Controller action accordingly

I have a controller action which has a class as a parameter.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(vm.Quotation quotationheaders)
{...
and calls it using
var token = $('input[name="__RequestVerificationToken"]').val();
quotationheader.__RequestVerificationToken = token;
$.ajax({
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
url: '/someapp/quotation/create/',
data: quotation,
async: true,
success: function (response1) {
alert(response1);
},
error: function (error) {
ThrowException(error);
}
});
the data object contains members which also have nested array of details (qutoation header and product details). Using the code above I do not have problem with ANTIFORGERY filter. it seems the controller action reconizes it. However, the product detail properties of the quotaion (nested array of object) are all null. It wasn't able to Bind to the model although the header properties were passed accordingly.
So I did some modification and changed the data and stringify it.
data: JSON.stringify(quotation),
This time, the controller action cannot recognize the verification token. So I tried to remove the AntiForgery and saw that the details were bound accordingly.
As summary:
ajax data stringify: binding is ok but verification token is not recognized.
ajax data object: the verification token is verified and but the object detail collection properties are null.
Can any body suggest a rightful way to do this?
Thanks!

Calling ASP.NET MVC 4 Controller from Javascript

I'm calling an ASP.NET MVC 4 control method from Javascript (in a cshtml file) using $.ajax() as shown below
$.ajax({
url: '#Url.Action("MyAction", "MyController")',
type: 'GET',
data: { 'id': "123"},
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function (data) {
}
});
The controller action method is
public JsonResult MyAction(string id)
{
// Do stuff
return new JsonResult();
}
which is getting called ok but is causing a GET 500 (Internal Server Error).
I don't really care about the returned data I just want to call the controller method to update a model.
Can anyone let me know why I'm getting the 500 or an alternative way of doing this that would be great.
For security reasons you cannot use the GET method in ajax requests (See JSON Hijacking).
You just have to do it like this:
return Json(data, JsonRequestBehavior.AllowGet)
or better off, change the method to post
type: 'POST',

Calling controller method (ASP MVC3) method from ajax doesn't work

I am using the following syntax to make a call to controller method from ASP page.
$.ajax({
url: 'ControllerName/MethodName',
type: 'POST',
contentType: 'application/json;',
data: JSON.stringify({ param: param1}),
success: function () {
alert("Success!!!");
},
error: function () {
alert("Failed!!!");
}
});
I have two ASP pages (views), both having same controller. If I call above method from first page, controller method gets called successfully. But if call same method from second page I get alert message "Failed". Also I tried using GET type, tried with other controller methods and all. Nothing will be called from second view. can anyone help me what can be problem? I am new to MVC.
Since your ajax is expecting result of JSON data from your Controller method do you have return Json(data, JsonRequestBehavior.AllowGet)?
Try change content type to:
contentType: 'application/json; charset=utf-8'
or/and specify url using mvc helper like:
url: #Url.Action("action"),
Works in my example. Hope it will help.

Resources