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

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.

Related

array data not being sent to API controller 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.

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)
{
//...
}

How to send a Object composed by Models and List (or IEnumerable) Models using $.ajax?

this is my model object
public class VentaProd
{
public IEnumerable<product> ListadoProductos {get; set;}
public IEnumerable<account> ListadoClientes { get; set; }
public sale Venta { get; set; }
}
If I use this code
$.ajax(
{
type: "Post",
dataType: "html",
url: '#Url.Action("buscarproducto", "detalle")',
data: {
vp: #Model.Venta.id
},
success: function (data) {
$('#divbuscar').html(data);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("algo salio mal" + errorThrown);
}
}
);
the before code works but my controller receive a null object, and if i change this code
data: {
vp: #Model.Venta.id
},
by
data: {
vp: #Model
},
the controller method is never called
unfortunately I could not use the first code because
my object VentaProd is not saved in database and this does not have a Id.
this is the controller method
public ActionResult buscarproducto(ejercicio1.Models.ClasesCombinadas.VentaProd vp=null)
{
return PartialView(vp);
}
If you only want to send back the ID the selection, you need to change the signature of the controller method to match the type of the id only:
public ActionResult buscarproducto(int? id=null)
If you want to have the model as a whole come back to the existing controller method you have, then you need to encode it:
vp: #Json.Encode(Model.Venta)

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.

De serialising JSON in webmethods

Based on the following code...
A user can come along and add as many 'outgoings' as they like via a separate function. I then add a new 'li' to the DOM and auto generate the txt ID
<ul id="ulOutgoing">
<li>
<label>Outgoing 1</label><input type="text" id="txtOutGoing0">
</li>
<li>
<label>Outgoing 2</label><input type="text" id="txtOutGoing1">
</li>
</ul>
At the end of the users path i need to send all txt values and labels to the server to firstly save to a db then generate a response based on the supplied data.
var OutGoings = {};
$('#ulOutgoing').find('li').each(function () {
var obj = {};
obj.text = $(this).find('label').html();
obj.value = $(this).find('input').val();
OutGoings.OutGoing = obj;
});
var DTO = { 'OutGoings': OutGoings };
function callBack(response) {
//Handel my webmethods response
}
ajaxCall(DTO, 'visualise-my-outgoings.aspx/getPieData', callBack, false);
My web method needs to accept the JSON Object and make it usable so I can loop over the txt value and labels and perform some db interactions and further logic
[WebMethod]
public static string getPieData(OutGoings OutGoings)
{
//Handel the object
}
public struct OutGoings
{
}
So... I have two questions
Am i creating the correct JSON object to push to my web method
How do I deserialise the object in my webmethod and what structure should my 'OutGoings' struct take?
You probably need a collection of OutGoing:
public class OutGoing
{
public string Label { get; set; }
public string Value { get; set; }
}
in your page method:
[WebMethod]
public static string GetPieData(OutGoing[] outGoings)
{
// Handle the object
return "Hello World";
}
and finally the client simply fill this collection by looping through the li elements:
var outGoings = $('#ulOutgoing li').map(function() {
return {
Label: $('label', this).html(),
Value: $('input', this).val()
};
}).toArray();
and then POST it to the page method:
$.ajax({
url: 'visualise-my-outgoings.aspx/GetPieData',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ outGoings: outGoings }),
success: function(result) {
// TODO : process the results
alert(result.d);
}
});
The JSON.stringify method is what properly serializes the javascript array into a JSON string. It is natively built-in modern browsers. If you need to support legacy browsers you might need to include the json2.js script to your page.
Don't use a struct, use a class. C# will handle the deserialization for you. You want something like:
[WebMethod]
public void getPieData(OutGoings[] outGoings)
{
// loop over array, interact with db
}
public class OutGoings
{
public string Text{ get; set; }
public string Value{ get; set; }
}

Categories