I'm trying to get filtered data from server using a filtering object I pass to the server side. I have managed to get this working with a post:
angular:
var filter: { includeDeleted: true, foo: bar };
$http({ method: 'post', url: 'api/stuff', data: filter });
web api:
public IEnumerable<StuffResponse> Post([FromBody]Filter filter)
{
return GetData(filter);
}
But i don't want to use a post for this, I want to use a get. But this does not work:
angular
$http({ method: 'get', url: 'api/stuff', params: filter });
web api
public IEnumerable<StuffResponse> Get([FromUri]Filter filter)
{
return GetData(filter);
}
Also tried specifying params: { filter: filter }.
If i try [FromBody] or nothing, filter is null. With the FromUri i get an object at least - but with no data. Any ideas how to solve this, without creating input parameters for all filter properties?
Yes you can send data with Get method by sending them with params option
var data ={
property1:value1,
property2:value2,
property3:value3
};
$http({ method: 'GET', url: 'api/controller/method', params: data });
and you will receive this by using [FromUri] in your api controller method
public IEnumerable<StuffResponse> Get([FromUri]Filter filter)
{
return GetData(filter);
}
and the request url will be like this
http://localhost/api/controller/method?property1=value1&property2=value2&property3=value3
Solved it this way:
Angular:
$http({
url: '/myApiUrl',
method: 'GET',
params: { param1: angular.toJson(myComplexObject, false) }
})
C#:
[HttpGet]
public string Get(string param1)
{
Type1 obj = new JavaScriptSerializer().Deserialize<Type1>(param1);
...
}
A HTTP GET request can't contain data to be posted to the server. What you want is to a a query string to the request. Fortunately angular.http provides an option for it params.
See : http://docs.angularjs.org/api/ng/service/$http#get
you can send object with Get or Post method .
Script
//1.
var order = {
CustomerName: 'MS' };
//2.
var itemDetails = [
{ ItemName: 'Desktop', Quantity: 10, UnitPrice: 45000 },
{ ItemName: 'Laptop', Quantity: 30, UnitPrice: 80000 },
{ ItemName: 'Router', Quantity: 50, UnitPrice: 5000 }
];
//3.
$.ajax({
url: 'http://localhost:32261/api/HotelBooking/List',
type: 'POST',
data: {order: order,itemDetails: itemDetails},
ContentType: 'application/json;utf-8',
datatype: 'json'
}).done(function (resp) {
alert("Successful " + resp);
}).error(function (err) {
alert("Error " + err.status);});
API Code
[Route("api/HotelBooking/List")]
[HttpPost]
public IHttpActionResult PostList(JObject objData)
{ List<ItemDetails > lstItemDetails = new List<ItemDetails >();
dynamic jsonData = objData;
JObject orderJson = jsonData.itemDetails;
return Ok();}
Related
I have an array in JS ( var selectedEmails = []; )
After I collect the selected Emails from a grid, I call a GET to C# controller:
$.ajax({
type: 'GET',
url: '#Url.Action("SendEmailBatchs", "account")',
data: { emails: selectedEmails },
contentType: 'application/json',
success: (data) => {
console.log("data", data);
}
})
When called, the parameter in C# gets no data. I've checked in JS, and the emails are in the array. Using breakpoints, I've confirmed the Controller's method is getting called:
Controller:
[HttpGet("sendemailbatchs")]
public async Task<ActionResult> SendEmailBatchs(string[] emails)
{
...
foreach (ApplicationUser user in users)
{
await SendEmailConfirmation(user);
}
return Ok;
}
Changing the data to data: { emails: JSON.stringify(selectedEmails) }, will pass an array with 1 element only, containing a stringified list of emails "[\"loes.vea#phanc.com\",\"MaAlonso.Mfizer.com\",\"cech#mll-int.cm\",\"jier.aris#si.com\"]"
What would be the correct parameter from JS so that I get a string ARRAY where each email is an element of the array?
emails = [0]: "loes.vea#phanc.com\",
[1]: \"MaAlonso.Mfizer.com\", ...
There is a gap between what you are expecting in the controller and what you are sending through ajax call.
public async Task<ActionResult> SendEmailBatchs(string[] emails)
Let's understand the parameter of the above function, you are expecting an array of strings and will refer to it as emails in the function body. So, you will have to pass an array of strings in the request body.
PFB my simple controller and corresponding ajax call:
[HttpGet("api/test")]
public ActionResult<int> RecieveData(string[] emails)
{
return emails.Count();
}
Call from UI like this:
var settings = {
"url": "https://localhost:5000/api/test",
"method": "GET",
"headers": {
"Content-Type": "application/json"
},
"data": JSON.stringify([
"john#example.com",
"jane#example.com"
]),
};
$.ajax(settings).done(function (response) {
console.log(response);
});
so, after following Devesh's suggestions I ended up with
var settings = {
"url": '#Url.Action("SendEmailBatchs", "account")',
"method": "GET",
"headers": {
"Content-Type": "application/json"
},
"data": {
emails: JSON.stringify(selectedEmails)},
};
the issue persisted, because I needed to DESERIALIZE the result, in C#:
public async Task<ActionResult> SendEmailBatchs(string emails)
{
var selectedEmails = JsonConvert.DeserializeObject<string[]>(emails);
//DO STUFF
}
Thx
I've tried all other solutions pertaining to the problem, but still can't find what i'm missing for my code. Here's my AJAX() Code.
var group = JSON.stringify({ 'listofusers': listofusers });
console.log("listofusers : " + JSON.stringify({ 'listofusers': group }));
(Assuming I have my listofusers object ready, and yes i've checked the console and it has data inside.)
$.ajax({
contentType: 'application/json; charset=utf-8',
dataType: 'json',
type: "POST",
url: url,
data: group,
success: function (data) {
console.log("output : " + JSON.stringify(data));
//doSend(JSON.stringify(data));
//writeToScreen(JSON.stringify(data));
},
error: function (data) {
console.log("error : " + JSON.stringify(data));
},
});
Here's my Server Side Controller.
[HttpPost]
public IActionResult GetMesssage(List<UserModel> listofusers)
{
var g = listofusers;
}
Just a simple fetch from the controller, so I could verify that the data from client side has really been sent.
I've tried the [FromBody] attribute, but still no luck in fetching the data from the server-side.
Here is a working demo like below:
1.Model:
public class UserModel
{
public int Id { get; set; }
public string Name { get; set; }
}
2.View(remove Content-type):
<script>
var listofusers = [
{ id: 1, name: 'aaa' },
{ id: 2, name: 'bbb' },
{ id: 3, name: 'ccc' }
];
var group = { 'listofusers': listofusers };
console.log(group);
$.ajax({
dataType: 'json',
type: "POST",
url: "/home/GetMesssage",
data: group,
success: function (data) {
console.log("output : " + JSON.stringify(data));
},
error: function (data) {
console.log("error : " + JSON.stringify(data));
},
});
</script>
3.Console.log(group):
4.Result:
Update:
Another way by using json:
1.View(change group from JSON.stringify({ 'listofusers': listofusers });
to JSON.stringify(listofusers);):
<script>
var listofusers = [
{ id: 1, name: 'aaa' },
{ id: 2, name: 'bbb' },
{ id: 3, name: 'ccc' }
];
var group = JSON.stringify(listofusers);
console.log(group);
$.ajax({
contentType:"application/json",
dataType: 'json',
type: "POST",
url: "/home/GetMesssage",
data: group,
success: function (data) {
console.log("output : " + JSON.stringify(data));
},
error: function (data) {
console.log("error : " + JSON.stringify(data));
},
});
</script>
2.Controller(add FromBody):
[HttpPost]
public IActionResult GetMesssage([FromBody]List<UserModel> listofusers)
{
//...
}
You can try this one.
First stringify the parameter that you want to pass:
$.ajax({
url: url,
type: "POST",
data: {
listofusers: JSON.stringify(listofusers),
},
success: function (data) {
},
error: function (error) {
}
});
Then in your controller:
[HttpPost]
public IActionResult GetMesssage(string listofusers)
{
var jsonModel = new JavaScriptSerializer().Deserialize<object>(listofusers); //replace this with your deserialization code
}
What we're doing here is passing your object as a string then deserializing it after receiving on the controller side.
Hope this helps.
I found the solution to my problem guys, but I just want a clarification that maybe there's a work around or another solution for this one.
I've studied the data passed by "JSON.stringify();" from AJAX() and it's somehow like this.
"[[{\"ID\":0,\"UserID\":1014,\"Level\":\"support\",\"Department\":\"\",\"Facility\":\"Talisay District Hospital\",\"Firstname\":\"Joseph\",\"Middlename\":\"John\",\"Lastname\":\"Jude\",\"LoginStatus\":false,\"IPAddress\":\"192.168.110.47:12347\"},{\"ID\":0,\"UserID\":1014,\"Level\":\"support\",\"Department\":\"\",\"Facility\":\"Talisay District Hospital\",\"Firstname\":\"Joseph\",\"Middlename\":\"John\",\"Lastname\":\"Jude\",\"LoginStatus\":false,\"IPAddress\":\"192.168.110.47:15870\"}]]"
to which I was wondering that if the JSON format is a factor in parsing the data from the controller side. (Which of course is stupid since there's only one JSON format. (or maybe there's another, if there is, can you please post some source for reference.))
so I tried Serializing a Dummy Data in my model in "JsonConvert.Serialize()" Method and the output JSON data is like this.
[{"ID":0,"UserID":1014,"Level":"support","Department":"","Facility":"Talisay District Hospital","Firstname":"Joseph","Middlename":"John","Lastname":"Jude","LoginStatus":false,"IPAddress":"192.168.110.47:12347"},{"ID":0,"UserID":1014,"Level":"support","Department":"","Facility":"Talisay District Hospital","Firstname":"Joseph","Middlename":"John","Lastname":"Jude","LoginStatus":false,"IPAddress":"192.168.110.47:16709"}]
and I tried sending the output JSON Data from JsonConvert.Serialize() Method to controller via AJAX() and it worked! And I feel so relieved right now as this problem was so frustrating already.
If there's something wrong with what I found, please respond with what might be wrong or correct. Thank you!
I wrote an angular quiz and I'm trying to send the quiz results to the database for processing. My $http call is as follows:
function saveQuiz() {
quizObj.isSaving = true;
var data = {
id: quiz_id,
action: 'quiz_data',
part: 'save_quiz',
score: quizObj.score,
passed: quizObj.passed,
completed: quizObj.completed,
percentage: quizObj.perc,
time_spent: $filter('formatTimer')(quizObj.counter),
questions: quizObj.quiz.questions
};
console.log(data);
$http({
url: quizapp.ajax_url,
method: "POST",
params: data
})
.then(function(response) {
console.log(response.data);
quizObj.isSaving = false;
},
function(response) { // optional
// failed
console.log(response);
});
}
Notice I am passing an array of json questions as quizObj.quiz.questions.
The problem on the server side is that $_POST['questions'] evaluates to the last item of the quizObj.quiz.questions json object instead of the full list.
Where have I gone wrong?
When using the $http service through Angular, data goes with method: "POST" and params goes with method: "GET"
Change the properties on your config object you are passing to the $http service like so:
$http({
url: quizapp.ajax_url,
method: "POST",
data: data // <-- data here, not params since using POST
}).then(function () { /*...*/ }));
To add query parameters to a url using jQuery AJAX, you do this:
$.ajax({
url: 'www.some.url',
method: 'GET',
data: {
param1: 'val1'
}
)}
Which results in a url like www.some.url?param1=val1
How do I do the same when the method is POST? When that is the case, data no longer gets appended as query parameters - it instead makes up the body of the request.
I know that I could manually append the params to the url manually before the ajax request, but I just have this nagging feeling that I'm missing some obvious way to do this that is shorter than the ~5 lines I'll need to execute before the ajax call.
jQuery.param() allows you to serialize the properties of an object as a query string, which you could append to the URL yourself:
$.ajax({
url: 'http://www.example.com?' + $.param({ paramInQuery: 1 }),
method: 'POST',
data: {
paramInBody: 2
}
});
Thank you #Ates Goral for the jQuery.ajaxPrefilter() tip. My problem was I could not change the url because it was bound to kendoGrid and the backend web API didn't support kendoGrid's server paging options (i.e. page, pageSize, skip and take). Furthermore, the backend paging options had to be query parameters of a different name. So had to put a property in data to trigger the prefiltering.
var grid = $('#grid').kendoGrid({
// options here...
dataSource: {
transport: {
read: {
url: url,
contentType: 'application/json',
dataType: 'json',
type: httpRequestType,
beforeSend: authentication.beforeSend,
data: function(data) {
// added preFilterMe property
if (httpRequestType === 'POST') {
return {
preFilterMe: true,
parameters: parameters,
page: data.page,
itemsPerPage: data.pageSize,
};
}
return {
page: data.page,
itemsPerPage: data.pageSize,
};
},
},
},
},
});
As you can see, the transport.read options are the same options for jQuery.ajax(). And in the prefiltering bit:
$.ajaxPrefilter(function(options, originalOptions, xhr) {
// only mess with POST request as GET requests automatically
// put the data as query parameters
if (originalOptions.type === 'POST' && originalOptions.data.preFilterMe) {
options.url = options.url + '?page=' + originalOptions.data.page
+ '&itemsPerPage=' + originalOptions.data.itemsPerPage;
if (originalOptions.data.parameters.length > 0) {
options.data = JSON.stringify(originalOptions.data.parameters);
}
}
});
I've got an ajax post being constructed like this:
var myData = [
{
id: "a",
name: "Name 1"
},
{
id: "b",
name: "Name 2"
}
];
$.ajax({
type: 'POST',
url: '/myurl/myAction',
data: { items: myData },
dataType: 'json',
error: function (err) {
alert("error - " + err);
}
});
And an MVC controller:
[HttpPost]
public JsonResult MyAction(MyClass[] items)
{
}
MyClass is just a simple representation of the data:
public class MyClass {
public string Name {get; set; }
public string Id {get; set; }
}
When the javascript makes the post request, the controller action does indeed receive 2 items, however the properties (id, name) in these items are null.
Checking the request in fiddler, the body looks like this:
Name | Value
items[0][Name] | Name 1
items[0][Id] | a
items[1][Name] | Name 2
items[1][Id] | b
Have I missed something?
Have I missed something?
Yes, take a look at the following article to understand the correct wire format that the default model binder expects for binding collections. In other words, for this to work, instead of:
items[0][Name] | Name 1
items[0][Id] | a
items[1][Name] | Name 2
items[1][Id] | b
your payload should have looked like this:
items[0].Name | Name 1
items[0].Id | a
items[1].Name | Name 2
items[1].Id | b
Unfortunately with jQuery it can be quite frustrating to achieve this payload. For this reason I would recommend that you use a JSON payload if you want to send complex objects/arrays to your server with AJAX:
$.ajax({
type: 'POST',
url: '/myurl/myAction',
data: JSON.stringify({ items: myData }),
contentType: 'application/json',
error: function (err) {
alert("error - " + err);
}
});
Things to notice:
data: JSON.stringify({ items: myData }) instead of data: { items: myData }
Added contentType: 'application/json'
Gotten rid of dataType: 'json'
Now your payload looks like this:
{"items":[{"id":"a","name":"Name 1"},{"id":"b","name":"Name 2"}]}
you can use this code to solve the problem :
$.ajax({
url: '/myurl/myAction',
data: { '': items },
method: "POST",
dataType: 'json',
success: function (xhr, status, response) {
},
error: function (xhr, status, response) {
}
});
[HttpPost]
public JsonResult MyAction(IEnumerable<MyClass> items)
{
}