I followed this tutorial to create a Restful web-api service.
Everything seemed to work well, I can get all the bookings in JSON format by requesting them from the correct url.
My issue is with the http POST.
My Javascript is:
var url = 'http://localhost:9077/api/bookings';
....
var newEvent = [];
newEvent.EventDateTime = // (now);
newEvent.Name = "MyFirstBooking";
function btnSubmit_Click()
{
alert("Submit clicked: " + newEvent.Name + "\n" + newEvent.EventDateTime);
$.ajax({
type: "POST",
url: url,
data: JSON.stringify( { Bookings: newEvent }),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) { alert(data); }
});
}
The alert displays the correct date and also the correct name.
When I click Submit and check fiddler it looks like the JSON is correctly formatted:
{"Bookings":[{"Name":"MyFirstBooking","EventDateTime":"2014-04-14T13:45:00.000Z"}]}
My View is Bookings.cs :
public class Bookings
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime BookingDateTime { get; set; }
public DateTime EventDateTime { get; set; }
public int Duration { get; set; }
public int UserID { get; set; }
}
In my BookingsController I have:
public HttpResponseMessage PostBooking(Bookings item)
{
// Implementation
}
However when I put a breakpoint after PostBooking, item.EventDateTime is {01/01/0001 00:00:00} and Name is null.
It seems like the JSON is not being deserialised correctly...? I'm not sure where this happens as I can't find it mentioned anywhere...
Thanks.
ahhh dates in javascript. Aren't they fun? You are more than likely going to have to do a converstion either in javascript or take a look at this stack overflow question to implement a custom date handler in your api:
ASP.NET Web API Date format in JSON does not serialise successfully
EDIT: Ahh i also noticed that your JSON object is an array. You will need to change your signature to take an array:
public HttpResponseMessage PostBooking(IEnumerable<Bookings> items)
{
// Implementation
}
EDIT AGAIN:
on second thought, I dont think your event needs to be an array. I think you want to do this:
var newEvent ={};
this will intialize newEvent as an object instead of a an array. then you can leave your signature as is. You might need to change your param name like tomasofen mentioned in his answer as well.
EDIT AGAIN:
further thought: you dont need to root the object with {"Bookings": newEvent } just do this instead:
$.ajax({
type: "POST",
url: url,
data: JSON.stringify(newEvent),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) { alert(data); }
});
you are setting the contentType to json. This tells your web app that the content should be json, which in turn will be handled and converted by the server. By stringifying it, you are turning the content into a string and therefore changing the contentType.
Try using the same name for the variable in the server method than the name of the Json parameter:
For server side:
public HttpResponseMessage PostBooking(Bookings item)
{
// Implementation
}
For client side (just change "item" as name of the param):
{"item":[{"Name":"MyFirstBooking","EventDateTime":"2014-04-14T13:45:00.000Z"}]}
I had issues with this, and perhaps this is your case. Tell us if it works or not to try other things.
Check also that the object Bookings in the server has the members Name and EventDateTime writen in the same way.
Related
I am using JSGrid to allow me to modify data. I am trying to setup the updateItem as follows:
updateItem: function (item) {
return $.ajax({
type: "PUT",
url: "/api/data/" + item.logID,
data: item,
contentType: "application/json;charset=utf-8",
dataType: "json"
});
}
I have a model as follows:
public class LogEntry
{
public string firstName { get; set; }
public string lastName { get; set; }
public string comment { get; set; }
public bool modified { get; set; }
public DateTime inTime { get; set; }
public DateTime outTime { get; set; }
public double totalHrs { get; set; }
public int logID { get; set; }
}
Here is my ApiController Class that contains the Put method:
public class DataController : ApiController
{
public void Put(int id, [FromBody]LogEntry item)
{
if(item != null)
{
//DO STUFF
}
}
}
However no matter what I do the item is always Null. I have tried the following:
Change to [FromBody]JObject item
Change to [FromBody]String item
Change the data: field to Json.Stringify
Change to [FromBody]String to just String
Add and remove context type of application/json;charset=utf-8 to the updateItem ajax call.
I have used Fiddler to see the data sent back. It shows the correct JSON being sent but the Put method doesn't seem to be getting that data.
Any ideas on what might be causing this behavior would be great. I have been researching around but nothing has worked yet.
Resolution Notes
It turned out that both answers from Caz1224 and CodeFuller aided in fixing this. CodeFuller's way of finding the error message lead me to the JSON coming back to the server. It was messed up even though Fiddler said it was correct. I changed my Ajax call to stringify the item. Which then matched my Model exactly.
return $.ajax({
type: "PUT",
url: "/api/data/" + item.logID,
data: JSON.stringify(item),
contentType: "application/json; charset=utf-8",
dataType: "json"
FromBody attribute is not strictly required here because non-simple types are built by the default from the request body.
I don't see any problems with your code so far, it should work for valid request. Seems like the problem is with the request sent and it causes model binding error. To proceed with the analysis check the following:
Check the value of ActionContext.ModelState.IsValid in Put() method. Is it true or false?
If it's false, check collection ActionContext.ModelState.Values in debugger. It should contain model binding errors that will hint you were the problem actually happens.
I had this issue and its painful!!
This is what ended up working for me.
The first part is my javascript (I guess that is how you are making your JSON)
"List" is my array that PERFECTLY matches (Even to the case, it matters) to my C# model.
Javascript Build List
var List = [];
$.each(_questions, function () {
var limitID = this.id.substr(-1);
var Quest = $('#Quest_' + ID).val();
var objectpush = {
LimitID: limitID,
Quest: Quest,
ID: ID
}
List.push(objectpush);
Then in the AJAX call further on I specify data like so:
data: JSON.stringify(List),
And finally this is on my C# API
public JsonResult QueryLimits(int UserID, [FromBody] List<List> List)
Hope this helps get you on the track. Don't just copy the code as I changed the name to List throughout my code and that will cause issues!
Caz
So, some time ago, I needed to make ajax requests to access the code behind. I did that (here).
But now I'm working on asp.NET Core 2.0 and it works differently. Well, now I can make a request but, for some reason The variables are null (only on the code behind, on the client side they have content. Probably isn't a big deal, but I can't grasp why.
So, here's my ajax function:
function Ajax(expression1, expression2, url, json, error) {
console.log(expression1+" - "+ expression2);
var request = { email: expression1, password: expression2 }
$.ajax({
url: url,
method: 'post',
contentType: 'application/json',
data: JSON.stringify(request),
dataType: 'json',
success: function (resp) {
console.log(request);
if (expression1 === null || expression2===null)
window.location.href = resp[json];
else
document.getElementById(error).innerHTML = resp[json];
},
error: function (error) {
}
})
}
And the c# code:
public string ExternalLogin(string email, string name)
{
//TODO: Facebook login
// Redirect link example. Could be another one.
return "{\"facebook\":\"Home/About\"}";
}
The ajax function makes the request and it triggers the c# function, and returns what I ask it to. The only problem is the null variables. Why is this happening?
EDIT: The User class as requested:
public class User
{
[JsonProperty(PropertyName ="email")]
public string Email { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "password")]
public string Password { get; set; }
}
The parameter binding fails because you are making a post request here.
You have to add the [FromBody] attribute to your parameters.
You can get more info about paramter binding here:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
EDIT:
You also passing a object as paramter so you either have to change you route paramter to an object containing email and password property, or you change your Content-Type to 'application/x-www-form-urlencoded' and pass a query string like 'email=....&password=....'
My raw json string passed to the MVC ActionResult Controller via AJAX post
{"ID":0,"RoutingRuleID":24,"ConditionalType":0,"Field":"Channel","ConditionalOperator":"5","Values":[1,9],"ValueString":""}
But what ends up happening is that once the json objects gets to the MVC controller it loses the values in the Associated Array "Values". The other properties are set correctly.
My model Class in C# is as follows:
public class RoutingConditional
{
public int ID { get; set; }
public int ParentID { get; set; }
public string ConditionalType { get; set; }
public string Field { get; set; }
public string ConditionalOperator { get; set; }
public List<string> Values { get; set; }
public string ValueString{get;set;}
public RoutingConditional()
{
//this.Values = new List<string>(); //I tried to initialize it too did not work
}
}
My MVC Controller
[HttpPost]
public ActionResult EditConditional(RoutingConditional rcview)
{
//rcview.Values = null
}
My Javascript
$.ajax({
url: actionURL,
type: "post",
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(myModel.RoutingConditional),
........standard success and error
});
Why is it being passed in as null for the array(List)?
This is a weird one, not sure I can fully explain (have an idea) but here's what I did.
Stripped out all your json parameters in the payload except the "Values":[1,9] and it worked just fine.
So started adding back each json parameter starting at the end (luckily). When I re-added "ValueString":"" it crapped out again.
So added a few more json params to see if it was an ordering issue (e.g., nothing can go after the array). That wasn't the case.
So started renaming stuff and when I renamed "ValueString":"" to something like "TmpValueString":"" it worked again.
Here's my best guess. The word ValueString has pieces of the name that match the first characters another property. In this instance, "values-tring" matches with "values" (array name) thereby throwing the MVC binder off when it goes to match against your object model. I'm not 100% on this, but that's what it seems.
So your solution is to rename one of your props so that its name does not make up the first characters of another prop.
Also, wanted to mention ConditionalOperator and ConditionalType names to counter any arguments. These names are unique in that they are not subsets of each other, but merely contain like characters. Whereas Values is a subset of Valuestring thus causing, what I think, is binding confusion.
Try setting the `traditional' option
$.ajax({
url: actionURL,
type: "post",
dataType: 'json',
traditional: true,
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(myModel.RoutingConditional),
........standard success and error
});
I have a json object like this:
var itemData = {
"translations":[
{
"value":"Byron",
"languageId":1
},
{
"value":"hgfdfghds",
"languageId":3
}
],
"itemId":204,
"itemCategoryId":44
};
And I POST it using jQuery like this:
$.ajax({
url: "items/update",
dataType: "json",
type: "POST",
data: itemData,
});
When the call arrives at my ASP.NET MVC4 controller action, the non-list properties are assigned. However, the translations array only has two empty objects (instantiated, but with null/default property values). Here is my controller action method and my models:
public JsonResult Update(UpdateItemModel model)
{
if(model.Translations[0].Value!="Byron")
{
throw new Exception("That translation's value should have been populated with 'Byron'.");
}
return Json("ok");
}
public class UpdateItemModel
{
public List<TranslationModel> Translations { get; set; }
public int ItemId { get; set; }
public int ItemCategoryId { get; set; }
}
public class TranslationModel
{
public string Value { get; set; }
public int LanguageId { get; set; }
}
If I look at Request.Form in the immediate window, I can see that the translations "array" is encoded for some reason (maybe that's correct, not sure). If I try Request.Form["translations"] I get null. Here's an example of the raw form data that I'm seeing:
{translations%5b0%5d%5bvalue%5d=Byron&translations%5b0%5d%5blanguageId%5d=1&translations%5b1%5d%5bvalue%5d=hgfdfghds&translations%5b1%5d%5blanguageId%5d=3&itemId=204&itemCategoryId=44}
Not sure if my problem has anything to do with the "encoding" of the json at the beginning of that string. I looked at it in Fiddler and saw the same thing, so I can't blame ASP.NET for tampering.
What could be the problem here?
You should specify the content type (json) and stringify it using JSON.stringify
$.ajax({
url: "items/update",
dataType: "json",
contentType: "application/json; charset=utf-8;",
type: "POST",
data: itemData,
data: JSON.stringify(itemData),
});
Another thing to do is use add a JsonValueProviderFactory:
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
in Application_Start method in Global.asax
This article might help you.
When you pass data for Ajax call is good to specify the content and stringfy the data:
$.ajax({
/*More stuff*/
data: JSON.stringify(itemData),
contentType: 'application/json',
dataType: "json",
type: "POST"
});
Then the value provider and the default ModelBinder will do the job.
I can see the json object properties are not matching .net properties, In json you have "value" in .net "Value" case is different. Try making the case to march the .net model
Here are my Classes (Simplified)
public class DailyMenu
{
public string MenuNoteText { get; set; }
}
public class MenuMonth
{
public DailyMenu[] DailyMenus { get; set; }
}
And My webApi Action is
[HttpPost]
public void AddMenuItem_New(MenuMonth menuMonth)
{
}
Clientside code for posting data is :
If I check Request.Form[0], I see "sampletext".
in menuMonth, DailyMenus[0] has 1 DailyMenu item... which seems correct.
but this item's MenuNoteText property is null :(
I spent more than half day trying to figure this out.. still no results ..
I am sure many must have posted a simple javascript object to server.. Can someone tell me what m I missing here ?
From the link:
application/x-www-form-urlencoded: Form data is encoded as name/value pairs, similar to a URI query string. This is the default format for POST.
Seems you forget to tell Web Api that you are sending request in json format, add 3 more headers and stringify your Json:
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(menuMonth),
Also note that there is one wrong typing: cache, not catche