array data not being sent to API controller c# - c#

I am working on angularJS application where I am making post call to send data to API controller everything is being sent to controller apart from array of data.
Here is code to make controller call
this.UpdateJobWithDeadlines = function (JobData) {
var request = $http({
method: "POST",
url: "/api/JobAPI/UpdateJobWithDeadlines",
data: JSON.stringify(JobData)
});
return request;
}
I have checked the JobData object, it's value (indented for easier reading) is:
{
"jobNum":null,
"jobName":"fgfg",
/* snip */
"StatusDatas":[
{
"scId":0,
"JobNum":9746.030148450296,
"StatusComment":"03-03-2017 : 1",
"scTimeStamp":"2017-03-03T15:47:48.174Z",
"IsNew":0
},
{
"scId":0,
"JobNum":8527.946898255957,
"StatusComment":"03-03-2017 : 3",
"scTimeStamp":"2017-03-03T15:47:49.459Z",
"IsNew":0
}
],
/* SNIP */
"telephone":"9"
}
The controller method signature is as below:
public int UpdateJobWithDeadlines(JobDataWithDeadlines JobData)
And the JobDataWithDeadlines class is as below:
public class JobDataWithDeadlines
{
public int? jobNum;
public string jobName;
/* snip */
public List<StatusData> StatusDatas;
}
public class StatusData
{
public int scId;
public int JobNum;
public string StatusComment;
public string scTimeStamp;
public bool IsNew;
}
But I am getting an empty list for the StatusDatas property of the controller method parameter.

The problem is your fields, they all need to be properties instead. The deserialization and serialization for json.net will not bind to fields (out of the box anyways, it is possible with additional configuration / custom mapping code).
public class JobDataWithDeadlines
{
public int? jobNum {get;set;}
public string jobName {get;set;}
/* snip */
public List<StatusData> StatusDatas {get;set;}
}
public class StatusData
{
public int scId {get;set;}
public double JobNum {get;set;}
public string StatusComment {get;set;}
public string scTimeStamp {get;set;}
public bool IsNew {get;set;}
}
Also you should specify the content-type in the http header of the request. In this case set it to application/json

You have to add the following properties to the object you pass to the $http method:
this.UpdateJobWithDeadlines = function (JobData) {
var request = $http({
method: "POST",
contentType: "application/json",
dataType: "json",
url: "/api/JobAPI/UpdateJobWithDeadlines",
data: JSON.stringify(JobData)
});
return request;
}
You can optionally specify a charset to the content type, i.e.:
contentType: 'application/json; charset=utf-8'
Some people also suggest adding traditional: true to it, but in my experience that is not always what causes this problem.

Related

C# MVC Ajax child lists

I have the following setup
HTML
$.ajax({
url: 'Transaction/updateTransaction',
data: saveDataObject,
}).done(function (e) {
// done
});
Which shows in the Network tab that it's sending the correct data
Querystring Parameters
key:2445
transactionDescription:Description Block
transactionToType[0][transactionToTypeKey]:1
transactionToType[0][transactionKey]:2445
transactionToType[0][transactionValue]:51.25
transactionToType[0][transactionTypeKey]:10
transactionToType[1][transactionToTypeKey]:2
transactionToType[1][transactionKey]:2445
transactionToType[1][transactionValue]:10.5
transactionToType[1][transactionTypeKey]:1
Controller
public class TransactionSave
{
public int key { get; set; }
public string transactionDescription { get; set; }
public List<TransactionToTypeSave> transactionToType { get; set; }
}
public class TransactionToTypeSave
{
public int transactionKey { get; set; }
public int transactionToTypeKey { get; set; }
public int transactionTypeKey { get; set; }
public decimal transactionValue { get; set; }
}
public int updateTransaction(TransactionSave transactionSave)
{
}
When doing a breakpoint in updateTransaction I can see transactionSave has all the data (key and description), and the transactionToType list has two items as expected, however, both of these list items, all of the values are 0.
e.g.
key:2445
transactionDescription: Description Block
transactionToType [
transactionToTypeKey:0
transactionKey:0
transactionValue:0
transactionTypeKey:0
], [
transactionToTypeKey:0
transactionKey:0
transactionValue:0
transactionTypeKey:0
]
What am I doing wrong to pass lists inside objects across ajax?
Thanks
It is failing because your ajax call is making a GET request.
If you do not specify the type proeprty when you use $.ajax method, it will make a GET call. For a GET call, the data will be appended as querystring key value items to the url you are making the ajax call to.
When sending a complex object which has child properties of other types, you should consider doing a POST request. query strings has a limit based on the browser. When the request is POST type, the data will be send in the request body.
This should work.
var saveDataObject =
{
key: 124,
transactionDescription:"My desc",
transactionToType: [{
transactionKey: 111,
transactionTypeKey: 164,
transactionValue:23.34
}
]
};
$.ajax({
type:'post',
url: '#Url.Action("updateTransaction","Transactions")',
contentType:"application/json",
data: JSON.stringify(saveDataObject)
}).done(function(e) {
console.log(e);
});
Make sure you marked your action method with [HttpPost] attribute
[System.Web.Mvc.HttpPost]
public ActionResult updateTransaction(TransactionSave transactionSave)
{
return Json(transactionSave);
}
Now it will send "application/json" as the contentType for the ajax request and the json stringified version of the js object will be in the request body. The model binder will be able to map the posted data to your object

Web API Json Deserialise

I am using Web Api.
I have an object of type A. when I return a list of type A to my client and then pass the list of type A back using a Post method the JSON serialisation and deserialisation is done automatically form me.
Because I want to pass multiple parameters using my POST method I have created a wrapper object with properties for each of the parameters I want to pass in. The JSON ser / DeSer is taken care of for this wrapper object, but how do I deserialise the JSON that represents my list of Type A within the wrapper object?
Thanks.
Added Code:
public class ConfigurationUpdateMessage
{
public string IpAddress { get; set; }
public List<object> Configurations { get; set; }
}
The Post method
public string PutUpdateConfigurations(ConfigurationUpdateMessage configMessage)
{}
Client Code
$scope.UpdateConfigs = function () {
$.ajax({
url: 'api/configurations',
dataType: "json",
type: "PUT",
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ IpAddress: "127.0.0.1", Configurations: $scope.configs }),
async: true,
processData: false,
cache: false,
success: function (data) {
},
error: function (xhr) {
}
});
};
PRE: Can you post some code?
If your wrapper object contains properties which match the types of the serialized objects the model binder should automatically deserialize them into the matching properties. Unless there's something wrong with the structure of the JSON you're POSTing.
You should create your same wrapper type on server-side.
For example:
public class OperationDTO
{
public string Parameter1 { get; set; }
public int Parameter2 { get; set; }
public IEnumerable<A> MyList { get; set; } //List<A> will also work too
}
Your Web Api action should look like this:
[HttpPost]
public IHttpActionResult Operation([FromBody] OperationDTO)
{
//...
}

ASP .NET MVC 4 binding json sent through ajax to custom class in controller not working correctly

I have following controller:
[HttpPost]
public JsonResult SaveCompensationComponent(int agencyId, CompensationComponentAllData compensationComponent)
{
int? id = _dmsCompensation.SaveCompensationComponent(agencyId, compensationComponent);
return Json(id, JsonRequestBehavior.AllowGet);
}
Definition of the CompensationComponentAllData class:
public class CompensationComponentAllData
{
some properties
...
public CompensationObject CompensationElement { get; set; }
public CompensationObject CompensationBasis { get; set; }
...
some properties
...
}
CompensationObject class:
public class CompensationObject
{
some properties
...
public ActivityData ByActivity { get; set; }
...
some properties
...
}
ActivityData class:
public class ActivityData
{
some properties
...
public List<int> GoalCategories { get; set; }
public List<int> Policies { get; set; }
...
some properties
...
public ActivityData() { }
public ActivityData(CompensationObjectByActivity record) {
...
}
}
In javascript I create appropriate objects and send that through ajax (contentType: 'application/json' and JSON.stringify used before sending data). Everything is correctly sent to server because I executed following code in the controller:
HttpContext.Request.InputStream.Seek(0, SeekOrigin.Begin);
var jsonStringData = new StreamReader(HttpContext.Request.InputStream).ReadToEnd();
And jsonStringData had correct value:
"{\"agencyId\":\"332\",\"compensationComponent\":{\"Id\":431,\"CompensationComponentInfoId\":509,\"AgencyJobPositionId\":\"306\",\"Name\":\"ggggggg44\",\"Description\":\"fdssssssss\",\"CompensationComponentImpactLevelId\":\"1\",\"CompensationProductionTypeId\":\"1\",\"CompensationFrequency\":{\"Id\":\"1\"},\"CompensationDateTypeId\":\"3\",\"EffectiveDate\":\"06/10/2015\",\"BasisDifferentThanElement\":false,\"CompensationElement\":{\"ObjectTypeId\":\"3\",\"ByActivity\":{\"CompensationAttributeId\":\"21\",\"UnitsId\":\"3\",\"PoliciesLevel\":\"Individual Company/Policy\",\"Policies\":[\"572\",\"139\",\"138\"],\"VerificationLevelId\":\"1\"}},\"CompensationBasis\":{\"ObjectTypeId\":\"3\",\"ByActivity\":{\"CompensationAttributeId\":\"21\",\"UnitsId\":\"3\",\"PoliciesLevel\":\"Individual Company/Policy\",\"Policies\":[\"572\",\"139\",\"138\"],\"VerificationLevelId\":\"1\"}},\"CompensationStructureId\":\"2\",\"CompensationRateId\":\"1\",\"FixedValue\":\"10.00\",\"UseChargeback\":false}}"
Now problem is that after binding compensationComponent.CompensationElement.ByActivity.Policies has a null value even though it should be a list with 3 elements.
What makes me even more confused is that in the same time compensationComponent.CompensationBasis.ByActivity.Policies is bound correctly. Also compensationComponent.CompensationElement.ByActivity.GoalCategories is bound correctly too.
EDIT:
This is my ajax call:
$.ajax({
type: type,
url: url,
data: JSON.stringify(data),
success: callback,
error: function (xhr, ajaxOptions, thrownError) {
...
},
contentType: 'application/json',
cache: cache
});
If I remove JSON.stringify and try something as suggested in this post I get error in binding so 500 is just returned.
Please help.
I think that's a little bit strange that you want to receive part of the JSON as method parameters. I think you need to introduce a class for root object:
public class CompensationModel
{
public int AgencyId { get; set; }
public CompensationComponentAllData CompensationComponent { get; set; }
}
And your controller method will take this class as a parameter:
[HttpPost]
public JsonResult SaveCompensationComponent(CompensationModel model)
I suggest you to use services like json2csharp, let's computer does the boring work.
And few comments about JSON that you send. JSON.stringify doesn't change types:
JSON.stringify({a: [1, 2, 3]}) // -> "{"a":[1,2,3]}"
JSON.stringify({a: ["1", "2", "3"]}) // -> "{"a":["1","2","3"]}"
So if you get strings in your JSON that menas that javascript values are of type string. In C# models you expect to have int, so you might consider to convert data in javascript, though MVC is smart enough to convert these values.

Why dosen't this javascript object convert to a C# class object?

I'm working on a little test bed app, where you give the app a note name, sign, and octave, and it spits out the frequency the note should sound at.
I'm having a problem with a JavaScript object that is sent to a server via AJAX. However, it does not map at all to the class on the action.
The sender code is a piece of JavaScript:
$someContainer.on('click', '.raise-pitch', function (e) {
e.preventDefault();
var $line = $(this).parents('.item-line'),
// Cache GUI elements for this line. Not pertinent.
var data = {
'model': {
'NoteName': $noteName.val(),
'Sign': $noteSign.val(),
'Octave': $noteOctave.val()
},
'steps': 1
};
var dataString = JSON.stringify(data);
$.ajax({
type: 'POST',
url: '#Url.Action("AlterPitch", "Home")',
data: dataString,
async: true,
dataType: 'json',
success: function (result) {
// Unimportant things.
}
});
});
In the data object, you can see that I have two things: the model and the steps. The steps determines how far we alter the musical note. I have verified that the values for note name, sign, and octave are making it into the data object. The steps are pre-determined.
The data object, however, maps to a ViewModel on the C# side, which looks like this:
public class NoteViewModel
{
public enum NoteSign
{
Natural,
Sharp,
Flat
}
public string NoteName { get; set; }
public NoteSign Sign { get; set; }
public int Octave { get; set; }
public float Frequency { get; set; }
private static readonly Dictionary<string, float> FrequencyLookup = new Dictionary<string, float>
{
{"C", 16.35f},
{"C#", 17.32f},
{"D", 18.35f},
{"D#", 19.45f},
{"E", 20.60f},
{"F", 21.83f},
{"F#", 23.12f},
{"G", 24.50f},
{"G#", 25.96f},
{"A", 27.50f},
{"A#", 29.14f},
{"B", 30.87f}
};
// Methods...not important for reasons below.
}
...which itself is encapsulated in a unique view model:
public class AlterPitchViewModel
{
public NoteViewModel model;
public int steps;
public NoteViewModel AlterPitch()
{
model.ChangeStep(steps);
return model;
}
}
...or at least it should. I set a break point in my controller method:
[HttpPost]
public ActionResult AlterPitch(AlterPitchViewModel model)
{
return Json(model.AlterPitch(), JsonRequestBehavior.AllowGet);
}
...But the model is null, which leads to a NullReference exception.
the model isn't serializing to an object that gets sent along in this context. Obviously I am still doing something wrong. Question is...what?
This approach has worked for me.
Server Side:
First, create your ViewModel
public class TestViewModel
{
public string Id { get; set; }
public string Description { get; set; }
}
Then, in the Controller:
[HttpPost]
public ActionResult TestingViewModel(TestViewModel udata)
{
// Stuff.
}
Client Side:
function CallTestingViewModel() {
// We create the javascript object based on the
// definition of our C# ViewModel class.
var udata = {
Id: 1,
Description: 'This is a test.'
};
// Calling the C# method via AJAX.
$.when(GenericAjaxCall('Home/TestingViewModel', false, udata)).then(function (result) {
// do stuff
});
}
// Return the AJAX call as a Promise Object
function GenericAjaxCall(controllerUrl, async, clientData) {
return $.ajax({
type: 'POST',
async: async,
url: controllerUrl,
data: JSON.stringify(clientData),
contentType: 'application/json;',
dataType: 'json'
});
}
Hope it helps.
Your HttpPost Method must have one unique parameter which is your ViewModel. My advice: create a viewmodel per post WebMethod.
So here:
public class AlterPitchViewModel
{
public NoteViewModel note { get; set; };
public int Steps { get; set; };
}
And adapt your Javascript accordingly. No need to name your javascript model instance as the parameter in the ASP method -> one object arrives and only one parameter is available so no ambiguity.

jQuery allways Post null to Action in MVC 4

I have a problem and I don't know what is the issue.
I am constructing a Json object and I want to post it back with $.ajax. The problem is I always get null in my Action.
here is Ajax Part :
$("input[type=button]#ajax-editor-save").click(function() {
var hotelPropertyAssignModel = new Object();
hotelPropertyAssignModel.Hotel_Id = 1;
hotelPropertyAssignModel.HotelProperties = new Array();
$("input.ajax-editor[data-edited=true]").each(function() {
var hotelPropertyValue = new Object();
hotelPropertyValue.HotelProperty_Id = $(this).attr("data-hotelPropertyId");
hotelPropertyValue.Language = $(this).attr("data-lang");
hotelPropertyValue.Value = $(this).attr("value");
hotelPropertyAssignModel.HotelProperties.push(hotelPropertyValue);
});
$.ajax({
url: '#Url.Action( "SetProperties" )',
type: 'POST',
dataType: 'json',
data: JSON.stringify(hotelPropertyAssignModel)
});
});
and here is Action:
[AcceptVerbs( HttpVerbs.Post )]
[HttpPost]
public void SetProperties ( string hotelPropertyAssignModel )
{
}
I changed the parameter to string to validate how json is coming. I get null when I replace it with correct model too!
anybody can help?
Make sure you set the proper contentType:
$.ajax({
url: '#Url.Action( "SetProperties" )',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(hotelPropertyAssignModel)
});
The dataType parameter that you were using indicates the response type, not the request type. You don't need it if your controller action properly sets the Content-Type response header which it normally does if you are returning for example a JsonResult.
But from what I can see your controller action is declared as void which obviously is wrong. Controller actions must return action results. If you don't care about the content, simply use an EmptyResult:
[AcceptVerbs( HttpVerbs.Post )]
[HttpPost]
public ActionResult SetProperties ( string hotelPropertyAssignModel )
{
...
return new EmptyResult();
}
Also there's another very serious problem with your controller action. It is taking a string argument instead of a view model!!! I don't know how you were possibly expecting to bind a JSON request to some string.
So, immediately define a view model that will match the JSON structure you are willing to send:
public class HotelAssignmentViewModel
{
public int Hotel_Id { get; set; }
public HotelPropertyViewModel[] HotelProperties { get; set; }
}
public class HotelPropertyViewModel
{
public int HotelProperty_Id { get; set; }
public string Language { get; set; }
public string Value { get; set; }
}
and then have your controller action take this view model as parameter:
[AcceptVerbs( HttpVerbs.Post )]
[HttpPost]
public ActionResult SetProperties ( HotelAssignmentViewModel model )
{
...
return new EmptyResult();
}
I also notice another problem with your code. You seem to have subscribed to the click event of some DOM element to trigger the AJAX request but you never cancel the default action by returning false from this event. So for example if this is a submit button or an anchor, it will simply redirect the browser away from the page leaving no time for your AJAX request to execute. So make sure you cancel this default action by returning false from your click handler:
$("input[type=button]#ajax-editor-save").click(function() {
...
return false;
});

Categories