De serialising JSON in webmethods - c#

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; }
}

Related

Updating Display based on dropdown

As part of a form, I need to display some data about an object from a dropdown. The user using the field is assigning a student to a section of a class, and will need to see the current count of open/filled seats in the class.
Currently, I am building my class drowndown like this:
#Html.DropDownList("Sections Available", new SelectList(Model.AvailableSections, "Id", "Name"))
and later I want to have a div that lists out the availability like:
Open Slots: #someVariable
Filled Slots: #someOtherVariable
This information is part of my Sections model that belongs to the VM for this page. Those look like:
public class ApproveStudentViewModel
{
public string FriendlyName { get; set; }
public List<Section> AvailableSections { get; set; }
public Guid UserId { get; set; }
}
public class Section
{
public Guid Id {get; set; }
public string Name {get; set; }
public int SpacesRemaining {get; set;}
public int SpacesTaken {get; set;}
}
I have a controller call available for getting the section by Id, but that is as far as I've gotten on figuring this out. I'm very new to using MVC and Razor in particular, and this sort of thing should not be as hard as it is appearing to be.
One way you could do this is by using jQuery if you are open to that.You can then make the jQuery AJAX function create a new Div based on the Section by ID. So changes to your code would be as follows:
#Html.DropDownList("SectionsAvailable", new SelectList(Model.AvailableSections, "Id", "Name"))
<div id="slot-information"></div>
The at the end of your Razor page you need to make sure that you are referencing jQuery
<script src="~/lib/jquery/dist/jquery.js"></script>
Now you can create an AJAX call to your controller function and send the sectionID as a parameter:
<script>
$("#SectionsAvailable").change(function () {
$.ajax({
type: "GET",
contentType: "application/json",
dataType: "json",
url: '#Url.Content("~/")' + "{ControllerName/GetSpaceInfo",
data: { sectionID: $("#SectionsAvailable").val() }, //id of the section taken from the dropdown
success: function (data) {
var items = '';
$.each(data, function (i, row) {
items += "<label> Open Slots: " + row.SpacesRemaining + "</label> <label> Filled Slots: " + row.SpacesTaken + "</label> ";
//To test in your browser console
console.log(row.SpacesTaken);
console.log(row.SpacesRemaining);
});
$("#slot-information").html(items);
},
error: function () {
alert("oops");
}
});
});
Finally in your controller (maybe SectionsController) create the following function to return the JSON object.
// returns a list of space available based on section
[HttpGet]
public ActionResult GetSpaceInfo(int sectionID)
{
List<Section> sect = new List<SSection>();
//Should only return 1 item to the JSON list
sect = _context.Sections.Where(m => m.Id == sectionID).ToList();
return Json(sect);
}
Haven't tested the code but this should do the trick. If it isn't working check the console in your browser.

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.

Categories