$.ajax POST/non post behaviour difference? - c#

I am attempting to send some data via JSON to a MVC controller action:
For some reason, this works:
var items = [];
$("input:checked").each(function () { items.push($(this).val()); });
//This works
$.ajax({
type: "POST",
url: url,
data: { listofIDs: items, personID: personID},
dataType: "json",
traditional: true,
success: function() {
//Rebind grid
}
});
//This listofIDs is ALWAYS null !? (longhand for `$.getJSON` ?)
$.ajax({
url: url,
dataType: 'json',
data: { listofIDs: items, personID: personID },
success: function () {
//Rebind grid
}
});
So why does it work at the top, but the bottom it is always null? The same code is used to build items !?
edit: controller method
public ActionResult AddJson(List<int> listofIDs, int personID)
{
if (listofIDs==null || listofIDs.Count < 1)
return Json(false, JsonRequestBehavior.AllowGet);
...
//Add something to database
//Return true if suceeed, false if not
}
edit: so I ended up solving it by just turning the array into a string and sending it that way. That way I was able to send more than just the array variable.
var items = $(':input:checked').map(function () { return $(this).val();}).toArray();
var stringArray = String(items);
$.ajax({
url: url,
dataType: 'json',
data: { listOfIDs: stringArray, personID: personID },
success: function () {
//rebind grid
}
});
Note no POST type needed to be set.

Without type: "POST" it defaults to GET (according to the docs), which your server side code is probably not expecting.
Also, you could get a list of the values with...
var items = $(':input:checked').map(function() {
return $(this).val();
}).toArray();
jsFiddle.
Not sure if it's better though. Just an idea I had :)

The problem is probably on the server side. In the first case you are using HTTP POST in the other HTTP GET. That means that you probably have to access the data differently. Maybe have a look at Get individual query parameters from Uri for the HTTP GET case.

You're not specifying the type of the request, so it defaults to GET.
From jQuery Docs:
The type of request to make ("POST" or "GET"), default is "GET".
Perhaps you meant to specify POST. If you send it using GET the array will be added into the QUERY_STRING like ?listofIDs=... and won't be accessible the same way you normally access POSTed data.

Related

why POST request method returns null but GET request returns correct object

This is my controller code :
[HttpPost]
public async Task<JsonResult> GetWebsite(int Id)
{
var website = await _uWebsitesService.GetWebsite(Id);
return (website == null ? this.Json("Website Not Found") : this.Json(website));
}
And this is my ajax :
$(".edit-website-btn").on("click", function () {
let id = $(this).attr('data-id');
$.ajax({
type: "POST",
url: "/userpanel/GetWebsite/",
data: { Id: id },
dataType: "json",
contentType: "application/json",
success: function (result) {
console.log(result);
},
error: function (error) {
console.log(error);
},
})
})
When I check the result in console log, it's null when request type is post but when I change The ajax request and controller method to GET it returns the correct object.
this is because for your post method you are using application/json content that doesnt send id to an action, so action is using id=0 by default and can't get any data. Get action has a correct id and returns data. you can try to fix ajax for post by removing contentType: "application/json"
$.ajax({
type: "POST",
url: "/userpanel/GetWebsite/",
data: { Id: id },
dataType: "json",
.....
but imho better to use GET
$.ajax({
type: "GET",
url: "/userpanel/GetWebsite?id="+id,
dataType: "json",
...
and maybe you should try this too
let Id = $(this).data('id');
//or
let Id = this.getAttribute('data-id');
Your data parameter in the ajax call is an object, which just so happens to have a property called Id with the value you want.
However, your C# method expects just an integer, not an object with a property called "Id".
Simply change the JavaScript to only post the integer.
data: id,
To also help out C#'s binding, you should also specify that the parameter is from the request's body. This is techinally optional, but might help with maintainability and ensuring your value doesn't accidently come in from another source (like a rouge query param).
public async Task<JsonResult> GetWebsite([FromBody] int Id)
If you need to pass more than one value in the POST call, you'll need to make a class in C# and bind that instead of the int.

ajax POST sending null

I originally wrote the call as a GET but found a limitation with the length of the URI. Ideally, the call will take an object and turns it into a JSON format string, then sends it to a controller which will encrypt that string. The controller will send back a true/false if it succeeded.
My problem with POST, once it reaches the controller, the data parameter set from the ajax is null.
Here is the ajax/js:
var encActionURL = '#Url.Action("Encrypt", "Home")';
$.ajax({
url: encActionURL,
type: "POST",
contentType: "application/json; charset=utf-8;",
dataType: "json",
async: true,
traditional: true,
data: { jsonDoc: JSON.stringify(jsonDataFile) },
success: /*OnSuccess*/ function (result) {
// DO STUFF;
}
});
Here is the controller:
[HttpPost]
public bool Encrypt(string jsonDoc)
{
return serverConnection.Encrypt();
}
Note that, when I simply change the type to 'GET', it works great but when the form gets too long, it throws a 414 status error.
Most of the fixes found that I seem to have is the 'application/json'. I've also set ajax to traditional.
After going through a rabbit-hole of security tokens and validating forms, it wasn't any of that... this might be a solution for anyone using ASP.NET Core 2.1 MVC (5?) or just in general. Could have been a syntax mistake, return type mistake, or a combination.
New Ajax
$.ajax({
url: encActionURL,
type: "POST",
data: { 'jsonDoc': JSON.stringify(jsonDataFile) }, // NOTICE the single quotes on jsonDoc
cache: false,
success: /*OnSuccess*/ function (result) {
// DO STUFF;
}
});
New Controller
[HttpPost]
public ActionResult EncryptJSON(string jsonDoc) // Switch to ActionResult, formerly JsonResult
{
return Json(serverConnection.Encrypt());
}

Passing a Var and List to Controller via Ajax

I have a Text Box and a Select Options Multiple, i store all the selected items using knockout selectedOptions in a viewModel.
If I try to pass the captured information to my Controller using ajax I'm unable to recieve my MetricsChosenModel.
var MetricsChosenModel= window.vm.MetricsChosenModel();
var ApplicationsNameValue = $.trim($("#add-Applications").val());
if (ApplicationsNameValue.length <= 0) {
$("#text-add-Applications").popover('show');
}
$.ajax({
url: '/Admin/AddApplications',
type: "POST",
dataType: "JSON",
data: { ApplicationsName: ApplicationsNameValue, MetricsChosenModel: MetricsChosenModel },
success: function (returndata) {
if (returndata == true) {
}
else {
}
},
error: function () {
}
});
My Controller
public ActionResult AddApplications(string ApplicationsName,List<string> MetricsChosenModel)
{
//Code here
return View();
}
My MetricsChosenModel stores data in following format
MetricsChosenModel[0] => 5
MetricsChosenModel [1] => 6
why am i not able to recieve the list value of MetricsChosenModel , I'm able to recieve the ApplicationsName though,
Also it would be great if some one can explain, how am i wrong here,
Thanks,
Without knowing what your routing looks like, it's hard to pinpoint the exact source of the problem. If I had to guess, I'd say that you're getting the ApplicationsName value through the URL (routing or querystring parameter). If that's the case, you could probably add the [FromBody] attribute to the MetricsChosenModel. Note, however, that you're only allowed one FromBodyAttribute per method signature. If you need more variables, a simple solution to this problem is to create a model which contains each of the properties you're looking to receive in your controller action.
Hope that helps!
I've run into this problem myself with ASP.NET MVC: sending a model with some fields and one or more arrays up to a controller would not properly get the array contents into the C# model. The following change to the ajax call fixes it for me every time:
$.ajax({
url: '/Admin/AddApplications',
type: "POST",
contentType: 'application/json; charset=utf-8', // ADD THIS
dataType: "JSON",
data: JSON.stringify({ ApplicationsName: ApplicationsNameValue, MetricsChosenModel: MetricsChosenModel }), // Also added JSON.stringify
success: function (returndata) {
if (returndata == true) {
}
else {
}
},
error: function () {
}
});
The 'content-type' and 'JSON.stringify' help MVC with converting the model. Please let me know if that helped for you too :)

Pass a collection to MVC controller via jquery

I'm using ASP.NET MVC3 with Jquery. I'm trying to pass my form elements back to the controller using something like this (Please note I removed success and error code for simplicity):
var formElements = $("#myForm").serialize();
$.ajax({
type: "POST",
url: ScriptResolveUrl("~/Report/SubmitChanges"),
data: {collection: formElements},
success:
error:
dataType: "json"
});
My question is what should the parameter in my controller method look like:
Here is my controller method:
public ActionResult SubmitChanges(WHAT GOES HERE?)
{
}
So what I'm really looking for is what should be the type of the parameter going into the controller method? I want to be able to retrieve the values of the form elements in the controller.
So here is what I did. I have about 20-30 elements on my form so I really didn't want to have to turn each one into a parameter or list them all out in the collection.
In the jquery, I did the following:
var formElements = $("#myForm").serialize();
$.ajax({
type: "POST",
url: ScriptResolveUrl("~/Report/SubmitChanges"),
data: { parms: formElements },
success:
error:
dataType: "json"
});
It then goes into my controller as a string:
public ActionResult SubmitChanges(string parms)
I then found a function to parse that string (seems to be working)
NameValueCollection qscoll = HttpUtility.ParseQueryString(parms);
This seems to work without listing out all of the form elements.
Assuming your form elements all correspond to your model (let's say it's MyModel), then it should simply be:
public ActionResult SubmitChanges(MyModel model)
{
}
MVC default model binding will do the rest :).
Make sure you change your data definition in the jQuery ajax method though, you've already serialized it. Just do:
data: formElements,
I'm assuming the following in your jQuery ajax method is a copy and paste error?
success:
error:
If it's not, then make sure you either remove it, or change them to:
success: function (result) {
//do something
},
error: function () {
//do something on error
}
The problem is that their is no model that corresponds to my form
elements.
Then you can have this:
public ActionResult SubmitChanges(int id, string name)
{
}
And then pass in the individual items:
var o = {
id = $("#id_elem_id").val(),
name = $("#name_elem_id").val()
}
$.ajax({
type: "POST",
url: ScriptResolveUrl("~/Report/SubmitChanges"),
data: JSON.stringify(o),
success:
error:
dataType: "json"
});
where id_elem_id and name_elem_id are the ids of your html elements. And add any additional parameters you need, just follow along.
You were almost there. Just get rid of the brackets around your data parameter:
var formElements = $('#myForm').serialize();
$.ajax({
type: 'POST',
url: ScriptResolveUrl("~/Report/SubmitChanges"),
data: formElements,
success: function(result) {
// handle the success of the AJAX request
},
error: function() {
// an error occurred
}
});

jQuery posts null instead of JSON to ASP.NET Web API

I can't seem to get this to work... I have some jQuery like this on the client:
$.ajax({
type: "POST",
url: "api/report/reportexists/",
data: JSON.stringify({ "report":reportpath }),
success: function(exists) {
if (exists) {
fileExists = true;
} else {
fileExists = false;
}
}
});
And in my Web.API controller I have a method like this:
[HttpPost]
public bool ReportExists( [FromBody]string report )
{
bool exists = File.Exists(report);
return exists;
}
I'm just checking to see if a file lives on the server, and to return a bool as to whether it does or not. The report string I am sending is a UNC path, so reportpath looks like '\\some\path\'.
I can fire the script okay, and hit a breakpoint in my ReportExists method, but the report variable is always null.
What am I doing wrong?
I also see a way to post with .post and postJSON. Maybe I should be using one of those? If so, what would my format be?
Update: An additional clue maybe- if I remove [FromBody] then my breakpoint doesnt get hit at all- 'No http resource was found that matches the request'. Examples I am looking at show that [FromBody] isn't needed...?
So I found the problem, and the solution. So, first thing first. The contentType cannot be 'application/json', it has to be blank (default to application/x-www-form-urlencoded I believe). Although it seems you have to SEND json, but without a name in the name value pair. Using JSON.stringify also messes this up. So the full working jQuery code is like this:
$.ajax({
type: "POST",
url: "api/slideid/reportexists",
data: { "": reportpath },
success: function(exists) {
if (exists) {
fileExists = true;
} else {
fileExists = false;
}
}
});
On the Web.API side, you MUST have the [FromBody] attibute on the parameter, but other than this it's pretty standard. The real problem (for me) was the post.
In Fiddler, the request body looked like this "=%5C%5Croot%5Cdata%5Creport.html"
This post really had the answer, and linked to this article which was also very helpful.
jQuery.ajax() by default sets the contentType to be application/x-www-form-urlencoded. You could send the request in application/json instead. Also, you should send your data as a string and it will get model bind to the report parameter for your post method:
$.ajax({
type: "POST",
url: "api/report/reportexists/",
contentType: "application/json",
data: JSON.stringify(reportpath),
success: function(exists) {
if (exists) {
fileExists = true;
} else {
fileExists = false;
}
}
});
This worked for me, all other approaches didn't:
function addProduct() {
var product = { 'Id': 12, 'Name': 'Maya', 'Category': 'newcat', 'Price': 1234 };
$.ajax({
type: "POST",
url: "../api/products",
async: true,
cache: false,
type: 'POST',
data: product,
dataType: "json",
success: function (result) {
},
error: function (jqXHR, exception) {
alert(exception);
}
});
}
Serverside:
[HttpPost]
public Product[] AddNewProduct([FromBody]Product prod)
{
new List<Product>(products).Add(prod);
return products;
}
If you're using MVC's FromBody attribute, the MVC binder treats this as an optional parameter. This means you need to be explicit about the Parameter names even if you've only got a single FromBody parameter.
You should be able to work with something as simple as this:
Controller:
[HttpPost]
public bool ReportExists( [FromBody]string report )
{
bool exists = File.Exists(report);
return exists;
}
Javascript:
$.ajax({
type: "POST",
url: "api/report/reportexists/",
data: { "report":reportpath },
success: function(exists) {
...
You must ensure that your data object in jQuery matches the parameter names of your Controllers exactly.
$.post served the purpose for me. Remove the [FromBody] from webapi and give the url in the url parameter of the $.post in jquery client. It worked!

Categories

Resources