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

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.

Related

How to pass List<T> from from JS to API

I have below model and Controller. I want to know how to pass value for the API from Ajax call.
Model:
Public Class Data
{
public int ID {get;set;}
public string Title {get;set;}
}
Controller:
[HTTPPOST]
public string UpsertItems(List<Data> Inputs)
{
try
{...}
catch(Exception ex)
{..}
}
From frontend i need to pass below data to API.
I tried passing data like below
var datacoll='{{"ID":1,"Title":"a"},{"ID":2,"Title":"b"}}'
If I pass variable datacoll as it is I am getting 500 internal error and if I pass JSON.Stringify(datacoll) in controller i am getting null value.
Ajax method:
$.ajax({
url: '/Test/UpsertItems',
method: 'POST',
dataType: 'text',
contentType: 'application/json; charset=utf-8',
data: datacoll,
success: function (data) {..},
error: function (jqXHR) {..},
});
Please let me know what is wrong in it.
Looks like your data needs to be a list, notice the square brackets.
var datacoll='[{"ID":1,"Title":"a"},{"ID":2,"Title":"b"}]'

Returning data objects from ajax query to controller

I'm attempting to access data from a form and pass it to a controller in MVC.
I was successful in passing the data when I get the element by ID and pass as string:
This works:
data: JSON.stringify({
'Answer0': $("#Answer0").val(),
'Answer1': $("#Answer1").val(),
'Question0': $("#Question0").val()
}),
However I want to bring the data in as a viewmodel. When I specify the request as:
data: JSON.stringify($('#' + formDiv).serializeObject()),
It will populate the viewmodel, however there are fields that are not bound to the ViewModel that I would like to pass along with the serialized form. I have tried just adding them, but they don't seem to come in if I pass both the serialized form object and the additional string.
function clickedNext(e, formDiv) {
var sURL = '#Url.Action("SurveySave", "Home")'
$.ajax({
url: sURL,
type: "POST",
contentType: 'application/json',
data: JSON.stringify($('#' + formDiv).serializeObject(), { 'Answer0': $("#Answer0").val(), 'Answer1': $("#Answer1").val() }),
success: function (data) {
//$('#InvestigationStatus').html(data);
}
});
Controller
[HttpPost]
public ActionResult SurveySave(SurveyViewModel s, string Answer0, string Answer1)
I feel like you can't put two objects inside of JSON.stringify();
Maybe try something like:
var bothObjects = {
$('#' + formDiv).serializeObject(),
{ 'Answer0': $("#Answer0").val(), 'Answer1': $("#Answer1").val() }
}
...
JSON.stringify(bothObjects),

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.

MVC3 Get Ajax Posted Values

in postback requests when i need posted values i do like this
[HttpPost]
public ActionResult Index()
{
//i need to get values in here not in action method argument
//i know this works but not like this --> ActionResult Index(string Name)
string Name = Request.Form["Name"];
}
but in ajax requests this does not work,,and i cant find where mvc store ajax posted values
Any Suggestions?
I'm a little late to the party, but I will offer an alternative that will allow you to access Request.Form with an Ajax post/form. This was tested in MVC 4 and jQuery 1.9.1.
If the controller's Request.Form is not populating for your Ajax post, it is likely because you are manually serializing and sending the data to the controller with a contentType of application/json (a common scenario).
Here is an jQuery.ajax example that will NOT populate Request.Form on the controller.
// JSON serialized form data.
var data = {"id" : "1234", "name" : "Dave"};
$.ajax({
type: "POST",
url: serviceUrl,
contentType: "application/json",
dataType: "json",
data: JSON.stringify(data || {}),
success: function () { }
});
Changing the contentType will cause the controller to process the post like a form submission.
// Form encoded data. See jQuery.serialize().
var data = "id=1234&name=Dave";
$.ajax({
type: "POST",
url: serviceUrl,
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
dataType: "json",
data: data,
success: function () { }
});
You can also leave contentType undefined as application/x-www-form-urlencoded; charset=UTF-8 it is the jQuery default.
I would note that I only used $.ajax to better illustrate what is going on. You could also use $.post, though you will still need to send form encoded data
The ajax posted values won't appear in the request from collection however you can use the ValueProvider infrastructure in MVC to get the your Ajax posted value:
[HttpPost]
public ActionResult Index()
{
Name = ValueProvider.GetValue("Name").AttemptedValue;
}
Or the Request.InputStream contains all the posted data what you can read and deserailize as you want:
[HttpPost]
public ActionResult Index()
{
var serializer = new JavaScriptSerializer();
using (var streamReader = new StreamReader(Request.InputStream))
{
var data = (Dictionary<string,object>)serializer
.DeserializeObject(streamReader.ReadToEnd());
//assuming your posted data looks like this: '{"Name": "test"}'
string name = data["Name"].ToString();
}
}
But I highly recommend that you should not fight against the MVC infrastructure and recive the data as your action paratemer:
[HttpPost]
public ActionResult Index(string name)
{
}

Render Partial View using Jquery Ajax with variable data

I have already read this post, but I am not sure know to make it work taking data from the user. Here is the ajax jquery I am using. I know (or at least think) that this cant render a partial. But it works all the way until the render fails. I thought it may be helpful to have.
$.ajax(
{
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: "{'test':" + "'" + dateText + "'}",
dataType: 'json',
url: 'Site/Grab/',
success: function (result) {
alert('Success');
},
error: function (error) {
alert('Fail');
}
});
Here is my controller
[HttpPost]
public ActionResult Grab(string test)
{
DateTime lineDate= Convert.ToDateTime(test);
List<Info> myInfo= GameCache.Data(lineDate);
return PartialView("_PartialView", myInfo);
}
Okay, couple of things to try:
1) dataType is the expected result of the ajax call. In your case, your sending JSON, but receiving HTML. The content-type parameter specifies the request, which you have (and what you have is correct). So the data type should be:
dataType: 'html',
2) You need to serialize the JSON. Try grabbing the lightweight JSON library and stringify'ing:
var test = { test: 'testvalue' };
$.ajax {
...
data: JSON.stringify(test),
...
});
Much easier than trying to coerce a JSON string with quoatations. Create a regular JS variable, then stringify it.
The rest of your code looks fine.
If it's a problem with the HTML/markup of the partial view itself, run in debug mode and Visual Studio should stop on the line in the markup that is causing the problem.
Bonus Hint: ASP.NET MVC 3 includes built-in JSON model binding. So you can create a basic POCO that matches the fields of your JSON object, then accept it as a strongly-typed object in the action method:
[HttpPost]
public ActionResult Grab(MyJsonObject obj)
{
DateTime lineDate= Convert.ToDateTime(obj.test);
List<Info> myInfo= GameCache.Data(lineDate);
return PartialView("_PartialView", myInfo);
}
Since your only sending one parameter, it's overkill - but if you have more than 2 then it's worthwhile using a JSON POCO.
Change your controller code to:
public ActionResult Grab(string test) {
DateTime lineDate= Convert.ToDateTime(test);
List<Info> myInfo= GameCache.Data(lineDate);
return Json(new { data = this.RenderPartialViewToString("_PartialView", myInfo) });
}

Resources