JSON passing as a null to a method argument - c#

I finally tried to try my hand at using KnockoutJS. I explored for shorter ways to send JSON data to a C# method in MVC 4, but ended up using the AJAX method instead. I have some confusion around the following and was hoping someone could help.
Javascript
var VM = function () {
var self = this;
self.ValidateAndCreate = function () {
console.log("entered");
var a = {
b: "1",
c: "2",
d: {
e: "3"
}
};
var input = { data: a }
console.log(JSON.stringify(input));
$.ajax({
url: '/McAfee/ValidateAndCreatePartner',
data: JSON.stringify(input),
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (result) {
console.log('success');
}
});
}
}
var viewModel = new VM();
ko.applyBindings(viewModel);
C#
[HttpPost]
public void ValidateAndCreatePartner(string data)
{
var x = JsonConvert.DeserializeObject(data);
RedirectIfSuccess();
}
What currently happens is that the ValidateAndCreatePartner fires, but the argument data is null, followed by NewtonSoft.Json.JsonConvert.DeserializeObject failing as a result. How can I resolve this issue?

The easiest way in MVC is to create class as per your data : it is much cleaner! For example, with your example, you can try this :
[HttpPost]
public ActionResult Test(TestClass data) {
RedirectIfSuccess();
}
public class TestClass
{
public string b { get; set; }
public string c { get; set; }
public TestSubClass d { get; set; }
}
public class TestSubClass
{
public int e { get; set; }
}

Since your content type is application/json, the argument to the view function will be automatically deserialized (it's not a string anymore).
Create a viewmodel on the server side matching the one you send and use it as the type argument of the view:
public class D {
public string e {get;set;}
}
public class A {
public string b {get;set;}
public string c {get;set;}
public D d {get;set;}
}
[HttpPost]
public void ValidateAndCreatePartner(A data)
{
// no need to deserialize data
RedirectIfSuccess();
}

Related

Pass dynamic key value pair data from AJAX to controller gives null value

I try to pass dynamic key value pair data from AJAX controller. Key and Value both are not fixed.
My AJAX call:
var lstJson = [];
$('#divjson').find('.jsonKeyValue').each(function(index, element) {
var key = $(this).find(".key").val();
var value = $(this).find(".value").val();
var lst = {};
lst.key = key;
lst.value = value;
lstJson.push(lst);
});
console.log(lstJson);
SecureAjaxCall.PassObject({
url: `${MyHostURL}/Localization/SaveJsonData`,
dataType: 'json',
data: JSON.stringify({
lstJson: lstJson
}),
success: function(data) {
alert('success');
}
});
Other AJAX parameter's like dataType: 'json',, type: 'POST',... comes dynamically that's not a problem.
When I see on devtool , It's post data:
{
"lstJson":[
{
"key":"create",
"value":"Banauhos"
},
{
"key":"btnGetstarted",
"value":"SuruGarnuhos"
},
{
"key":"titleOne",
"value":"Sirsak1"
},
{
"key":"data",
"value":"Tathyanka"
}
]
}
My controller:
[HttpPost]
public string SaveJsonData([FromBody] GetlocalizeValue lstJson)
{
// Other code to Save data but lstJson gives always null value
return "Success";
}
My getters and setters:
public class GetlocalizeValue
{
public List<GetlocalizeValue> lstJson { get; set; }
public string key { get; set; }
public string value { get; set; }
public string FilePath { get; set;
}
But I always get null value on my controller (lstJson is always null)? Any help is much appreciated.
Your model must reflect the json object structure:
public class KeysAndValues
{
[JsonPropertyName("key")
public string Key { get; set; }
[JsonPropertyName("value")
public string Value { get; set; }
}
public class LocalizedValues
{
[JsonPropertyName("lstJson")]
public KeysAndValues[] ListJson { get; set; }
}
It is recommended to follow c# property naming conventions by capitalizing the first letters, and provide a property name for json.

Passing JSON to Controller MVC3 C# .NET

I´m trying to pass my data(json) from view through ajax to my controller but this arrive null. Thanks in advance fro any help or suggestion.
This is my model.
public class TipificacionModel
{
public int Existente { get; set; }
public string Campo { get; set; }
public int Regla { get; set; }
}
public class ListasSeleccionModel{
public List<string> DatosSeleccion { get; set; }
}
public class ListaTipificaciones
{
public string NombreCampaña { get; set; }
public List<TipificacionModel> Tipificacion { get; set; }
}
public class DatosSeleccionMultiple
{
public List<String> Columnas { get; set; }
public List<ListasSeleccionModel> ListasSeleccion { get; set; }
}
public class TipificacionGeneralCampaña
{
public ListaTipificaciones CamposCreados { get; set; }
public List<DatosSeleccionMultiple> ListasDeSeleccion { get; set; }
}
This is my ajax function.
jsonListaGeneral = [];
jsonListaGeneral.push(jsonTipificacion);
jsonListaGeneral.push(jsonListasSeleccion);
console.log(jsonListaGeneral);
$.ajax({
url: '#Url.Action("crearCampManual", "DPS")',
type: 'post',
data: JSON.stringify(jsonListaGeneral),
contentType: 'application/json; charset=utf-8;',
dataType: 'json',
success: function (response) {
alert(response)
return;
},
error: function (x) {
alert(x.responseText);
}
});
This is my controller.
[HttpPost]
public ActionResult crearCampManual(TipificacionGeneralCampaña model)
{ //Here the model value is null, why?}
When i print the json in my browser console everything is good. But something bad happends, im making something wrong.
Console Browser
Break Point Controller
One issue is that the data you are sending through your AJAX call appears to be an Array:
jsonListaGeneral = [];
But your C# model isn't an array or collection:
public ActionResult crearCampManual(TipificacionGeneralCampaña model)
If you are sending an array of TipificacionGeneralCampaña objects from your AJAX to your C# Controller, then you would want your Controller definition to look like this:
public ActionResult crearCampManual(List<TipificacionGeneralCampaña> model)
And also to reiterate what #Hackereman stated in his comment, you do not need to use the JSON.Stringify function on your data before you pass it to your Controller:
$.ajax({
url: '#Url.Action("crearCampManual", "DPS")',
type: 'post',
data: jsonListaGeneral,
contentType: 'application/json; charset=utf-8;',
dataType: 'json',
success: function (response) {
alert(response)
return;
},
error: function (x) {
alert(x.responseText);
}
});
Another issue that I noticed from your Console Browser screenshot: you seem to be adding two different objects to the same JSON array before sending to your controller:
jsonListaGeneral.push(jsonTipificacion);
jsonListaGeneral.push(jsonListasSeleccion);
When creating a collection in C#, all objects in the collect need to be of the same type, meaning that they have the same Property Names and Property Types.
With how your C# Controller is currently setup, it will accept a JSON object that is structured like this:
{
CamposCreados : {
NombreCampaña : "",
Tipificacion : [
{
Existente : 0,
Campo : "",
Regla : 0
},
{
Existente : 1,
Campo : "",
Regla : 1
}
]
}
ListasDeSeleccion : [
{
Columnas : "",
ListasSeleccion : [
{
DatosSeleccion : [
{
"",
"",
""
}
]
},
{
DatosSeleccion : [
{
"",
"",
""
}
]
}
]
}
]
}
The solution is change the declaration of the Json Object.
var jsonListaGeneral = {
"CamposCreados": jsonTipificacion,
"ListasDeSeleccion": jsonListasSeleccion
}

Diagnosing JS model binder issue in mvc from ajax

I can't figure out why my action param is coming through null. I'm also not sure of how to even diagnose the issue. I can see the http request data being sent with data and stepping through the debugger shows the object as null, not sure how to see the steps in between.
Models
public class ComplexObj
{
public int Id { get; set; }
public int Test1 { get; set; }
public decimal Test2 { get; set; }
}
public class BiggerObj
{
public BiggerObj()
{
ComplexObj = new List<ComplexObj>();
}
public long OtherId { get; set; }
public string Name { get; set; }
public ICollection<ComplexObj> ComplexObjs { get; set; }
}
Action
[HttpPost]
public void TestAction(BiggerObj[] biggerObjs)
{
...// biggerObjs is null :(
}
View
function ajaxCall() {
var data = [];
var bigObj = new Object();
bigObj.OtherId = 123;
bigObj.Name = "TestName";
bigObj.ComplexObj = [];
var complexObj = new Object();
complexObj.Id = 789;
complexObj.Test1 = 123;
complexObj.Test2 = 456;
bigObj.ComplexObj.push(complexObj);
data.push(bigObj);
}
}
$.ajax({
url: SITEROOT + "myController/TestAction",
cache: false,
type: 'POST',
data: data,
complete: function() {
alert('done');
}
});
}
Solved
You must use:
JSON.stringify and declare the contentType as "application/json; charset=utf-8"
Parse the decimal value by using parseFloat() function, decimal is considered as int by default binder.
Change your Action to this:
[HttpPost]
public ActionResult TestAction(BiggerObj[] biggerObjs)
{
...// biggerObjs is null :(
}
Change your ajaxCall function to this:
//ajaxCall
function ajaxCall() {
var data = [];
var bigObj = {
OtherId : 123,
Name : "TestName",
ComplexObjs : new Array()
};
var ComplexObjs = {
Id: 789,
Test1: 123,
Test2: parseFloat(456)
// decimal types are considered an integer, you have to parse
};
bigObj.ComplexObjs.push(ComplexObjs);
data.push(bigObj);
$.ajax({
url:"/Test/TestAction",
cache: false,
type: 'POST',
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
complete: function () {
alert('done');
}
});
}
I tested, works fine.

passing List and String data from ajax to controller in mvc 4, getting NULL for list?

Hi I'm new to JavaScript and MVC, and I'm trying to pass List and string to my controller.
JavaScript looks like:
var parms = {
globalList: globalList,
fieldName: fieldName
};
$.ajax({
//contentType: 'application/json; charset=utf-8',
type: "POST",
traditional: true,
url: "/Home/SaveField",
async: false,
data: parms,
dataType: "json",
success: function (data) {
console.log("uspjeh");
},
error: function (errorData) {
console.log("errors");
}
});
});
and controller looks like:
public void SaveField(List<Point> globalList, String fieldName)
{
// filedName is correctly passed
// list is null
}
can somebody help me please?
Point class:
public class Point
{
[Key]
public int PointId { get; set; }
public float GeoDuzina { get; set; }
public float GeoSirina { get; set; }
[ForeignKey("Data")]
public int DataId { get; set; }
public virtual Data Data { get; set; }
}
It wont work. If you debug a little then you will see that you post to server something like this:
globalList:[object Object]
globalList:[object Object]
globalList:[object Object]
It is just array of strings. But there is a way to do what you want.
You can serialize your array to json and then deserialize it in your controller. Just change your param to:
var parms = {
globalList: JSON.stringify(globalList),
fieldName: fieldName
};
And action:
[HttpPost]
public void SaveField(string globalList, string fieldName)
{
var serializer = new JavaScriptSerializer(); //use any serializer you want
var list = serializer.Deserialize<List<Point>>(globalList);
}
Or you can make param object looks like from HTML form:
var parms = {
"globalList[0].GeoDuzina": 51.506760996586294,
"globalList[0].GeoSirina": -0.06106463202740998,
"globalList[1].GeoDuzina": 51.516269286402846,
"globalList[1].GeoSirina": -0.056258113472722464,
"globalList[2].GeoDuzina": 51.50419662363912,
"globalList[2].GeoSirina": -0.044413478462956846,
fieldName: fieldName
};
It works with your action.
There are many other ways to do that. I just show two of them. Is any good for you?
btw. This numbers are too long for floats.;)

MVC4 JSON Model Binding doesn't work

Using the following Viewmodel :
public class GetUsersFromNextCircuitRequest
{
public int? dosarId { get; set; }
public List<int> dosareIds { get; set; }
public string query { get; set; }
public int page { get; set; }
public int page_limit { get; set; }
}
and using it in the following action:
public ActionResult GetUsersFromNextCircuit(GetUsersFromNextCircuitRequest requestNextUsers)
{
}
and send the request the following way:
ajax: { // instead of writing the function to execute the request we use Select2's convenient helper
url: self.attr('getusersfromnextcircuiturl'),
dataType: "json",
contentType: 'application/json; charset=utf-8',
type: 'POST',
traditional: true,
data: function (term, page) {
if (self.attr('dosare') !== undefined && self.attr('dosare').length > 0) {
var dosareIds = [];
self.attr('dosare').forEach(function (element, index, list) {
dosareIds.push(element.attr('Id'));
});
return JSON.stringify({
query: term, // search term
page: page,
dosareIds: dosareIds,
page_limit: 30
});
}
else
return JSON.stringify({
query: term, // search term
page: page,
dosarId: self.attr('dosarid'),
page_limit: 30
});
},
results: function (data, page) {
var more = (page * 30) < data.total; // whether or not there are more results available
return { results: data.users, more: more };
}
}
The http request looks like this:
{"query":"xa","page":1,"dosareIds":[4137,4163],"pagelimit":30}
The problem is that the request parameter is null. I have no idea why it doesn't work.
We had the same problem, then we decided to use CustomModelBinder. Am sharing what we have done,
In client side,
In ajaxRequest u need to send the entire ViewModel as below,
var viewModel = new Object();
viewModel.query= term;
viewModel.page= page;
viewModel.dosareIds= new Array();
viewModel.dosarIds = dosareIds;
viewModel.page_limit = 30;
then stringify the model and assign it to the data,
data: { viewModel: JSON.stringify(viewModel) };
In Server side,
U can use customModelBinder to retrive the value back
public class CustomJsonModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
try
{
var data = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
JavaScriptSerializer js = new JavaScriptSerializer();
var temp = js.Deserialize(data.AttemptedValue, bindingContext.ModelType);
return temp;
}
catch
{
return null;
}
}
}
And in ur viewModel u need to add the attribute,
[ModelBinder(typeof(CustomJsonModelBinder))]
public class GetUsersFromNextCircuitRequest
{
public int? dosarId { get; set; }
public List<int> dosareIds { get; set; }
public string query { get; set; }
public int page { get; set; }
public int page_limit { get; set; }
}
Now, CustomJsonModelBinder will parse the value. I hope it will solve ur prob.

Categories

Resources