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

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!

Related

ASP.NET Core jQuery POST - Incorrect Content-Type despite correctly formatted headers

I have researched similar threads, such as this one and this one, and have determined that this deserves its own thread, as I could not find any help in an hour of research.
I am trying to send a POST request to an ASP.NET Core host from a jQuery request. This is how I've formatted my POST request in the frontend:
$.ajax({
url: "/Merge",
type: "POST",
contentType: 'application/x-www-form-urlencoded',
datatype: "json",
data: {
"example": "examplecontent"
},
success: function (data) {
alert(data);
}
});
This is the way I'm ingesting it in the backend for testing purposes:
[HttpPost]
public IActionResult Index()
{
var x = HttpContext.Request.Form;
Dictionary<string, string> exampleDict = new();
//exampleDict.Add("Testing", HeaderElem);
JsonResult result = new(exampleDict);
return result;
}
Despite including complete headers, I have been getting this error on the backend claiming that I have an 'incorrect content type':
What might be wrong with my request?
you have to fix the action
[Route("~/Merge")]
public IActionResult Index(string example)
{
return Ok ( new { example = example } );
}

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 :)

Calling a C# method with jquery

I am trying to call a method with jQuery on a button click.This is waht I have so far:
$("a.AddToCart").click(function () {
var link = document.URL;
$.ajax({
type:"POST",
url: "/Account/AddToCartHack",
data: {url : link},
contentType: "application/json; charset=utf-8",
dataType: "json"
});
});
[WebMethod]
public void AddToCartHack(string url)
{
GeneralHelperClass.URL = url;
}
What I am trying to do here is when I click the link with class add to cart I want to call the method AddToCartHack and pass it the curent URL as a parameter.
I must be doing something wrong because it seems that AddToCartHack is not being called.
What am I doing wrong?
There are quite a lot of issues with your code, I don't know where to start. So let's conduct an interactive refactoring session with you (if you don't care about my comments but just want to see the final and recommended solution, just scroll down at the end of answer).
First: you don't seem to be canceling the default action of the anchor by returning false from the .click() event handler. By not doing this you are actually leaving the browser perform the default action of the anchor (which as you know for an anchor is to redirect to the url that it's href attribute is pointing to. As a consequence to this your AJAX call never has the time to execute because the browser has already left the page and no more scripts are ever running). So return false from the handler to give your AJAX script the possibility to execute and stay on the same page:
$("a.AddToCart").click(function () {
var link = document.URL;
$.ajax({
type:"POST",
url: "/Account/AddToCartHack",
data: {url : link},
contentType: "application/json; charset=utf-8",
dataType: "json"
});
return false;
});
Second: You have specified contentType: 'application/json' request header but you are not sending any JSON at all. You are sending a application/x-www-form-urlencoded request which is the default for jQuery. So get rid of this meaningless parameter in your case:
$("a.AddToCart").click(function () {
var link = document.URL;
$.ajax({
type:"POST",
url: "/Account/AddToCartHack",
data: {url : link},
dataType: "json"
});
return false;
});
Third: You have specified that your server side code will return JSON (dataType: 'json') but your server side code doesn't return anything at all. It's a void method. In ASP.NET MVC what you call C# method has a name. It's called a controller action. And in ASP.NET MVC controller actions return ActionResults, not void. So fix your contoller action. Also get rid of the [WebMethod] attribute - that's no longer to be used in ASP.NET MVC
public class AccountController: Controller
{
public ActionResult AddToCartHack(string url)
{
GeneralHelperClass.URL = url;
return Json(new { success = true });
}
}
Fourth: you have hardcoded the url to the controller action in your javascript instead of using server side helpers to generate this url. The problem with this is that your code will break if you deploy your application in IIS in a virtual directory. And not only that - if you decide to modify the pattern of your routes in Global.asax you will have to modify all your scripts because the url will no longer be {controller}/{action}. The approach I would recommend you to solve this problem is to use unobtrusive AJAX. So you would simply generate the anchor using an HTML helper:
#Html.ActionLink(
"Add to cart",
"AddToCartHack",
"Account",
null,
new { #class = "AddToCart" }
)
and then unobtrusively AJAXify this anchor:
$('a.AddToCart').click(function () {
var link = document.URL;
$.ajax({
type: 'POST',
url: this.href,
data: { url : link }
});
return false;
});
Fifth: You seem to be employing some document.URL variable inside your .click() handler. It looks like some global javascript variable that must have been defined elsewhere. Unfortunately you haven't shown the part of the code where this variable is defined, nor why is it used, so I cannot really propose a better way to do this, but I really feel that there's something wrong with it. Or oh wait, is this supposed to be the current browser url??? Is so you should use the window.location.href property. Just like that:
$('a.AddToCart').click(function () {
$.ajax({
type: 'POST',
url: this.href,
data: { url : window.location.href }
});
return false;
});
or even better, make it part of the original anchor (Final and recommended solution):
#Html.ActionLink(
"Add to cart",
"AddToCartHack",
"Account",
new { url = Request.RawUrl },
new { #class = "AddToCart" }
)
and then simply:
$('a.AddToCart').click(function () {
$.ajax({
type: 'POST',
url: this.href
});
return false;
});
Now that's much better compared to what we had initially. Your application will now work even with javascript disabled on the page.
place script method this way as shown below
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
Add Success and error function to check your ajax functionality
...
$.ajax({
type:"POST",
url: "/Account/AddToCartHack",
data: {url : link},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(){
alert('success');
},
error:function(){
alert('error');
}
});
....
If this is Asp.Net webforms you will need to make the webmethod static or the method cannot be accessed through JavaScript.
$(document).ready(function () {
$.ajax({
url: "Testajax.aspx/GetDate",
data: "f=GetDate",
cache: false,
success: function (content) {
$('#tableData').append('My Dear Friend');
alert(content);
},
failure: function (response) {
alert("no data found");
}
});
});

$.ajax POST/non post behaviour difference?

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.

Categories

Resources