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
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
I have an ASP.NET web api built into my MVC application and it currently receives all data accompanying a request as form encoded data.
I receive this as a FormDataCollection object and parse like so:
public string Post(FormDataCollection data)
{
var first = data.Get("FirstName");
//for every supported field.
}
My response is always a JSON string.
This is fine and I want to continue to accomodate this, however I'd like my users to be able to send a JSON with content type header application/JSON as well so that I can support both.
How do I accommodate both in a simple way? Will it have to involve checking the content header and having different code to extract the attributes in each case?
Let the asp.net model binder handle the bindings for you. Define a class that will represent your model:
public class Person
{
public string Firsname{ get; set; }
}
then have your controller action take this view model as argument:
public class PersonController : ApiController
{
public void Post(Person model)
{
...
}
}
Finally you can post using jquery ajax or whatever you pick. e.g
$.ajax({
type: 'POST',
url: '/api/person',
cache: false,
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ Firstname: "John Doe" }),
success: function() {
...
}
});
Try using a model class like below;
public class MyTargetModel
{
public string FirstName { get; set; }
}
public string Post(MyTargetModel model)
{
var first = model.FirstName;
//for every supported field.
}
When I say model class I mean a POCO class. ASP.NET MVC and Web API should be able to parse the request data in to the class as appropriate.
I am trying to map Json to Dictionary. Earlier I had Dictionary with key of type 'long' . But after realizing for mapping to happen key needs to be of type 'string or 'object'.
Now my type definition in c# is like this :
public class StyleItemCreateCommand
{
public long StyleId { get; set; }
public Dictionary<String, string> SelectedItemToColorMap { get; set; }
}
And json which I am generating is like this:
{"StyleId":"1710","SelectedItemToColorMap":{"1391":"583","21531":"7733"}}
But still somehow it is not being mapped. I am using asp.net mvc controllers as a service, which is being consumed by jquery client.
MVC method signature is as following:
[HttpPost]
public ActionResult Create(StyleItemCreateCommand command)
{
}
The dictionary object is always null. Any help is appreciated. Thanks.
Now after searching around web I found out that ASP.Net MVC is not gonna do it implicitly. Found this answer :
[https://stackoverflow.com/a/15220050/756722]
I think the reason why this is happening is that
"SelectedItemToColorMap":{"1391":"583","21531":"7733"}
is an object and your StyleItemCreateCommand
class defines a Dictionary. Change the class property to:
public object SelectedItemToColorMap { get; set; }
and you should be able to see the values. You can then redesign your class/es.
Alternatively amend the json by surrounding the { } with [ ] converts SelectedItemToColorMap to an array of key value items.
UPDATE
Just tried in asp.net mvc 4 with a simple view
<input type="button" value="click1" id="click1" />
#Scripts.Render("~/bundles/jquery")
<script>
$(function () {
//this is called by a Get action on the controller
$('#click1').click(function (e) {
var jsonObject = { "StyleId": "1710", "SelectedItemToColorMap": { "1391": "583", "21531": "7733" } };
$.ajax({
url: "#Url.Action("Create")",
type: "POST",
data: JSON.stringify(jsonObject),
contentType: "application/json; charset=utf-8",
dataType: "json",
error: function (response) {
//process error;
},
success: function (response) {
//process success;
}
});
});
});
</script>
The above appears in the body of the view. And the controller is
[HttpPost]
public ActionResult Create(StyleItemCreateCommand command)
{
if (command != null) {
string value1 = command.SelectedItemToColorMap["1391"];
string value2 = command.SelectedItemToColorMap["21531"];
Debug.Assert(value1 == "583" && value2 == "7733");
}
return View();
}
Which uses your StyleItemCreateCommand - and it all works. Ok the above uses JSON.stringify(jsonObject) so what format is your json object that is actually coming from the post request? It would be interesting to see the request body (eg using chrome developer tools under the network section).
.Net serialization (not being used here) will wrap requests in a .d object as a security measure against auto execution of code, could this be what is happening?
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.
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
});