How to pass complex JSON object in mvc action method? - ajax

I have a situation where I get data from ajax call. I want to call an action method and pass data as arguments. The data passed to action method should be mapped to object properties in parameter list.
Here is my class which is called FullQuestion.
public class FullQuestion : Question
{
public string Title { get; set; }
public string Content { get; set; }
public List<Tag> Tags { get; set; }
}
Here is my Ajax call method
var finalTagResultText = {Title: "title", Content: "content",Tag: { tagName: "tname", tagDescription: "tdesc"},Tag: { tagName: "tname1", tagDescription: "tdesc1"}};
$.ajax({
url: '#Url.Action("AskQuestion", "Dashboard")',
type: "POST",
data: JSON.stringify(finalTagResultText),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(result) {
window.location.href = "#Url.Action("Questions", "Dashboard")";
}
});
Here is my action method.
[HttpPost]
[ActionName("AskQuestion")]
public void AskQuestion_Post(FullQuestion question)
{
}
I want to get the JSON object passed as a FullQuestion object. I used json2 library to make use of stingify method.
I get the title and content text but no Tag object.
Any idea how can i accomplish that ? Thanks in advance.

Your collection property is named Tags (not Tag) and since its a collection, you need to pass an array of Tag objects, for example
var finalTagResultText = { .... , Tags: [{ tagName: "tname", tagDescription: "tdesc"}, { tagName: "tname1", tagDescription: "tdesc1"}]}`
Side note: Your ajax success callback is redirecting to another page, in which case, do not use ajax to submit your data. The whole point of ajax is to stay on the same page. You would be better off just doing a standard submit and using a RedirectToAction() in your POST method.

You are using wrong JSON format, using correct format as follows:
{"Title": "title", "Content": "content","Tag":[{ "tagName": "tname", "tagDescription": "tdesc"},{ "tagName": "tname1", "tagDescription": "tdesc1"}]}
In order to verify your JSON string, you can use the below link
https://jsonformatter.curiousconcept.com/

Related

Requesting Data from API Controller using GET with data as complex object

I have, until today always used POST to get response from API Controllers in .NETCore/MVC applications, but have been struggling with performance and have noted that POST cannot be cached...
So, I am trying to change things to use a GET request.
I do not like this, because I would prefer the data sent as a form, not in the URL... but if it must, it must
Anyway, I am having trouble getting .NET to serialize data posted using an object in the AJAX post (using jQuery or otherwise, I don't care)
My controller looks like this:
[HttpGet]
[Route("ProductStockHistory")]
public async Task< ChartResponse> ProductStockHistory([FromQuery] ChartQuery value)
{
//// do stuff
}
You can see I want to send a ChartQuery object, this looks like this:
public class ChartQuery
{
public string dateFrom { get; set; }
public string dateTo { get; set; }
public string groupBy { get; set; } = "month";
// more values...
}
Using a POST, I would do this: (with the [HttpGet] attribute changed to [HttpPost] and [FromQuery] changed to [FromBody])
$.ajax({
type: "POST",
url: "/Chart/" + chartAction,
contentType: "application/json",
dataType: "json",
data: JSON.stringify({
dateFrom : dateFromValue,
dateTo : dateToValue,
groupBy : groupByValue,
// more values...
}),
success: function (data) {
// do stuff
}
});
This works fine... but as per my opening statement, I cannot cache a POST request/response.
You can probably tell I am trying to get data for a chart, so it is not changing, therefore a cached response is adequate for me.
I have tried many variations of the AJAX code and the most logical to me looks like this:
$.ajax({
type: "GET",
url: "/Chart/" + chartAction,
contentType: "application/json",
dataType: "json",
data: { value: JSON.stringify({
dateFrom : dateFromValue,
dateTo : dateToValue,
groupBy : groupByValue,
// more values...
})},
processData: true,
success: function (data) {
// do stuff
}
});
This is generating a URL like: /Chart/ProductStockHistory?value=%7B"dateFrom "%3AdateFromValue%2C"dateTo"%3AdateToValue%7D, which looks about right, but .NET is not serializing the value, I'm getting a null/default object as value in my controller.
It's entirely possible that I am approaching it wrong, but how can I get a cached response when using a complex object as a value in a controller?
EDIT: note, I realise I could change the controller to receive individual values of the ChartQuery object, but that is not what I am trying to achieve
You dont need to call JSON.stringify on your ajax request. Something like this should work:
data:{
dateFrom : dateFromValue,
dateTo : dateToValue,
groupBy : groupByValue,
}
This should produce a request url like this:
/Chart/ProductStockHistory?dateFrom=dateFromValue&dateTo=dateToValue&groupBy=groupByValue
.net core binds those values then correctly to your ChartQuery model.

ASP.NET Core Api parameter is null

I have an API controller which has actions to get and post data. and I am trying to access GetProductById meyhod from ajax bu productId parameter is always equals to zero (0). When I want to call GetAll method with GET method everything is fine.
JavaScript code is like below
var product = JSON.stringify({ productId: id });
$http({
method: 'POST',
contentType: 'application/json',
url: '/api/Product/ProductInfo',
data: product
}).then(function successCallback(response) {
console.log(response);
}, function errorCallback(response) {
console.log(response);
});
And API Controller is like below
[Route("api/Product")]
public class ProductController : BaseController
{
[HttpPost]
[Route("ProductInfo")]
public Product GetProductById([FromBody]int productId)
{
return UnitOfWork.GetRepository<Product>().FirstOrDefault(i => i.Id == productId);
}
[HttpGet]
[Route("GetAll")]
public string GetAll()
{
return "Can";
}
}
Can anyone say why that case is happening?
Although you are sending back a string representation of { productId: id } when the model is binded in the post method in the controller it is expecting an int. productId is barely the argument of that method, it doesn't define the parameter name you're supposed to send. Try sending just the id in the body instead of that json body { productId: id }.
If you want to send back a json body then the proper representation should be a class like the following for your post action
class ProductModel
{
int productId;
}
This would essentially make you able to parse your json payload the way you send it now, of course you can opt for custom model binders but that would be an overkill.
For example, if the id is 123 just use 123 as body, not { productId: 123 }

MVC web api GET parameter is always null

Following is my ajax call
$.ajax({
type: "GET",
url: "https://localhost/api/Client",
data: JSON.stringify({"SortExpression":"clientName","SortDirection":"desc"}),
contentType: "application/json; charset=utf-8",
async: false,
cache: false,
dataType:'json',
error: function (data) {
alert("hi error buddy")
},
success: function (response) {
if (response) {
//todo
}
}
});
And my controller
public List<Customer> Get([FromUri] SortFilter filter)
{
}
and my model
public class SortFilter
{
public string SortExpression
{
get; set;
}
public string SortDirection
{
get; set;
}
}
but my contoller always takes the parameters as NULL. where am I going wrong ?
You're supplying a value, but not a key. So while the model binder may be able to discern what a SortFilter is, it has no way of knowing what filter is.
Try wrapping the object and giving it a key name. Perhaps something like this:
JSON.stringify({"filter":{"SortExpression":"clientName","SortDirection":"desc"}})
GET requests are performed on the query string, which should not be JSON encoded. POST, and PUT data may be JSON encoded, but not GET. The reason your parameter is null is because the query string is a single string with no parameter name.
replace:
data:JSON.stringify({"SortExpression":"clientName","SortDirection":"desc"})
with
data:{"SortExpression":"clientName","SortDirection":"desc"}
You can check the WebAPI call directly by typing in the full URL to the web API method
https://localhost/api/Client?SortExpression=clientName&SortDirection=desc
This will allow you to debug your data retriever, and page separately which should make the whole process much easier.

Ajax PUT request to Web Api

I currently have a ajax request setup to send a "PUT" request to a web api in my mvc 4 project. My request is able to get into the method on the api but the parameter is always null. Any ideas why? I have also check the PUT request as its executed and it does send a string of key/value pairs for each form control. Here is my code:
Web Api method (selection is always null)
public void Put([FromBody]string selection)
{
}
Update:
I forgot I was doing a little debugging of my own. I have confirmed that when you serialize a form the param is named "selection". Please take another look.
Ajax call:
$.ajax({
type: "PUT",
url: urlPrefix + "api/file/Manipulate",
data: $("#frmManipulate").serialize(),
contentType: "application/json; charset=utf-8",
dataType: "json",
statusCode: {
204: function (jqXHR) {
alert("No file(s)/Directory(s) were selected.");
}
}
}).done(function () {
location.reload();
});
It's null because you aren't passing it:
data: { val1 : "test", val2 : "test2"}
Try:
data: { selection : "something" }
It is null because asp.net web api does not know how to deserialize the { val1 : "test", val2 : "test2"} to a string. You could use a DTO approuch to pass these information to the action, for sample:
in the web api project, add a class like this:
public class InfoDTO
{
public string val1 { get; set; }
public string val2 { get; set; }
// other properties if you need
}
And change your put action to get a parameter with this type:
public void Put([FromBody]InfoDTO info)
{
// use 'info' object
}
Your client-side javascript can keep with the same code.

Parameter to Web Service via Jquery Ajax Call

I am using revealing module pattern and knockout to bind a form. When data is entered in that form(registration), it needs to be posted back to MVC4 web method.
Here is the Jquery code
/*
Requires JQuery
Requires Knockout
*/
op.TestCall = function () {
// Private Area
var _tmpl = { load: "Loading", form: "RegisterForm"};
var
title = ko.observable(null)
template = ko.observable(_tmpl.load),
msg = ko.observable(),
postData = ko.observable(),
PostRegistration = function () {
console.log("Ajax Call Start");
var test = GetPostData();
$.ajax({
type: "POST",
url: obj.postURL, //Your URL here api/registration
data: GetPostData(),
dataType: "json",
traditional: true,
contentType: 'application/json; charset=utf-8'
}).done(Success).fail(Failure);
console.log("Ajax Call End");
},
GetPostData = function () {
var postData = JSON.stringify({
dummyText1: dummyText1(),
dummyText2: dummyText2(),
});
return postData;
}
return {
// Public Area
title: title,
template: template,
dummyText1: dummyText1,
dummyText2: dummyText2
};
}();
The controller code is simple as per now
// POST api/registration
public void Post(string data)
{
///TODO
}
When i am trying to, capture the data (using simple console.log) and validate it in jslint.com, it's a valid Json.
I tried hardcoding the data as
data: "{data: '{\'name\':\'niall\'}'}",
But still i get as null, in my web method.
Added the tag [System.Web.Script.Services.ScriptMethod(UseHttpGet = false, ResponseFormat = System.Web.Script.Services.ResponseFormat.Json)] to my Post method in controlled, but still no fruitful result
Even tried JSON.Stringify data: JSON.stringify(data) but still i get null in my web-method.
I am not able to figure out the solution.
Similar issue was found # this link
http://forums.asp.net/t/1555940.aspx/1
even Passing parameter to WebMethod with jQuery Ajax
but didn't help me :(
MVC and WebApi uses the concept of Model Binding.
So the easiest solution is that you need to create a Model class which matches the structure of the sent Json data to accept the data on the server:
public void Post(MyModel model)
{
///TODO
}
public class MyModel
{
public string DummyText1 { get; set; }
public string DummyText1 { get; set; }
}
Note: The json and C# property names should match.
Only escaped double-quote characters are allowed, not single-quotes, so you just have to replace single quotes with double quotes:
data: "{data: '{\"name\":\"niall\"}'}"
Or if you want to use the stringify function you can use it this way:
data: "{data: '" + JSON.stringify(data) + "'}"

Resources