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.
Related
function myItemsViewModel(ItemID, GroupID, ItemName, Quantity) {
this.ItemID = ItemID;
this.GroupID = GroupID;
this.ItemName = ItemName;
this.Quantity = Quantity;
}
And i have below code for posting to the controller
var CreateRecord = function () {
var Name = $.trim($("#divCreate").find("#txtName").val());
var Department = $.trim($("#divCreate").find("#txtDepartment").val());
var ItemsList = [];
$('#myDynamicTable').find('tr').each(function () {
var row = $(this);
var itemName = $.trim(row.find(".itemName input").val());
var itemQty = $.trim(row.find(".itemQty input").val());
var myItems = new myItemsViewModel("", "", itemName, itemQty);
ItemsList.push(myItems);
});
var obj = new myRecordEntryViewModel("", Name, Department, ItemsList);
var viewmodel = JSON.stringify(obj);
$.ajax({
type: 'POST',
cache: false,
dataType: 'html',
data: viewmodel,
headers: GetRequestVerificationToken(),
contentType: 'application/json; charset=utf-8',
url: '/' + virtualDirectory + '/RecordEntry/Save',
success: function (data) {
$("#divMaster").html(data);
return false;
},
error: function (msg) {
alert("Error Submitting Record Request!");
}
});
}
At the line var viewmodel = JSON.stringify(obj);, viewmodel has all the values that i want in my ItemsList array variable.
Problem is my ItemsList array is coming as null in the controller. Name and Department are coming through with the correct passed values.
Below is my controller code.
Class
public class myRecordEntryViewModel
{
public long ID { get; set; }
public string Name { get; set; }
public string Department { get; set; }
public string[] ItemsList { get; set; }
}
Save action
[ActionName("Save")]
[NoCache]
public ActionResult Save(myRecordEntryViewModel viewModel)
{
//here viewModel.ItemsList is null, what could i be missing
if (this.SaveEntry(viewModel.Name,viewModel.Department,viewModel.ItemsList))
{
}
return this.View();
}
I'm wondering why viewModel.ItemsList is coming as null in controller yet it has values during the post from jQuery.
You should create a class for the Item in Item List (In C#)
public class Item {
public string ItemName { get; set; }
public int Quantity { get; set; }
}
And then change the viewmodel class
public class myRecordEntryViewModel
{
public long ID { get; set; }
public string Name { get; set; }
public string Department { get; set; }
//public string[] ItemsList { get; set; }
public List<Item> ItemsList {get ; set;}
}
The controller can not map the Item List from your request into model because one is a list of string and other is a list of object.
There are several problems in your codes...
1) ItemList in your class and your javascript code are not same - The frist one is an array of strings, and the second is an array of objects
2) In your action method, you should change parameter type like the following:
public ActionResult Save(string viewModel)
3) In the body of your action method, you should deserialize the json string (viewModel) and make the model object from it. The following is an example...
https://stackoverflow.com/a/17741421/1814343
Try the below code and see if your model gets the values.
Let me know if you face any problems, because I've already implemented this in one of my projects
var CreateRecord = function () {
var Name = $.trim($("#divCreate").find("#txtName").val());
var Department = $.trim($("#divCreate").find("#txtDepartment").val());
var model="";
var ItemsList = [];
$('#myDynamicTable').find('tr').each(function () {
var row = $(this);
var itemName = $.trim(row.find(".itemName input").val());
var itemQty = $.trim(row.find(".itemQty input").val());
var myItems = new myItemsViewModel("", "", itemName, itemQty);
ItemsList.push(myItems);
});
model = ['Name' : Name , 'Department' : Department , 'ItemsList' :ItemsList];
$.ajax({
type: 'POST',
cache: false,
dataType: 'html',
data: JSON.stringify(model),
headers: GetRequestVerificationToken(),
contentType: 'application/json; charset=utf-8',
url: '/' + virtualDirectory + '/RecordEntry/Save',
success: function (data) {
$("#divMaster").html(data);
HideLoader();
return false;
},
error: function (msg) {
alert("Error Submitting Record Request!");
HideLoader();
}
});
}
have tried the methods found but still cannot seem to tackle the issue.
am passing a list of object via Jquery Aja but it seems that the controller is receiving null values (it is recognizing the list count fine).
the jquery code is as follows:
var xmlids = Array();
for (var i = 0; i < orderId.length; i++) {
var xdata = {
"XmlOid": "" +orderId[i] + "",
"CourierCompany": $("#CourierCompany_"+orderId[i]).val() ,
"CourierService": $("#CourierService_" + orderId[i]).val(),
"StoreId" : storeId
};
xmlids.push(xdata);
}
var data = { invoices: xmlids };
$.ajax({
url: purl,
type: "POST",
dataType: "json",
//contentType: "application/json;",
async: false,
data: data,
The controller param is :
public JsonResult ProcessSaleOrder(List<XMLInvoiceGeneration> invoices)
the object is as follows:
public class XMLInvoiceGeneration
{
public Int64 XmlOid { get; set; }
public string CourierCompany { get; set; }
public string CourierService { get; set; }
public Int64? StoreId { get; set; }
}
any help appreciated.
I tried to replicate your problem.
I created a new ASP.NET MVC web application, and in the Home controller's Index view, I added the following
<input type="button" id="send" value="Send" />
#section scripts{
<script type="text/javascript">
$(function () {
$("input#send").on("click", function () {
var xmlids = Array();
for (var i = 0; i < 2; i++) {
var xdata = {
"XmlOid": 1,
"CourierCompany": "TempData",
"CourierService": "Temp",
"StoreId": 2
};
xmlids.push(xdata);
}
var data = { invoices: xmlids };
$.ajax({
url: "/Home/ProcessSaleOrder",
type: "POST",
dataType: "json",
async: false,
data: data
});
});
})
</script>
}
I basically created some temp data, but trying to still use your original idea. My controller looks like this:
[HttpPost]
public ActionResult ProcessSaleOrder(List<XMLInvoiceGeneration> invoices)
{
return new EmptyResult();
}
When I click the button, and hit the breakpoint in the controller, the invoices parameter contains 2 items, both with the values I set in the JavaScript code. I'm not sure why your code isn't working, but maybe you can use mine as a template to help you narrow down what the issue is.
Try this
uncomment //contentType: "application/json;",
And send data with JSON.stringify(data)
data: JSON.stringify(data)
PS: Best practice for url : url: "#Url.Action("method","controller")"
I had the same issue on sending a List to the controller. After a lot of effort, I found the reason why it is sending as null. It's the fields with Return Type(Class) that are not added with {get; set; }
$.ajax({
url: "/Home/CreateTasks",
data: ko.toJSON({Id: this.Id, tasks: objList }),
type: "POST",
dataType: "json",
processData: true,
contentType: "application/json; charset=utf-8",
success: data => {
}
And my Model Class is:
After
public class TaskFields
{
public string Title { get; set; }
public string Activity { get; set; }
}
public class CreateTaskInput
{
public int Id { get; set; }
public TaskFields TaskProperties { get; set; }
}
Before it was:
public class TaskFields
{
public string Title;
public string Activity;
}
public class CreateTaskInput
{
public int Id;
public TaskFields TaskProperties;
}
And My Controller Method is:
[HttpPost]
public JsonResult MethodName(int Id, List<CreateTaskInput> tasks)
{
}
I am not sure this answer will help you. But it may help someone who has a similar mistake. Thanks!
Add [FromBody] to the parameters in action
[HttpPost]
public ActionResult ProcessSaleOrder([FromBody] List<XMLInvoiceGeneration> invoices)
{
return new EmptyResult();
}
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.;)
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.
I have a bit of code where I'm trying to send a Viewmodel back to the controller using Ajax post. If I write the code one way, it passes correctly, and another way it returns null or 0 values within the viewmodel.
The way that works:
$(document).ready(function () {
$(".boxItem").change(function (event) {
var url = "/Search/GetBoxChangeInfo";
$.post(url, #Html.Raw(Json.Encode(Model)), function (data) {
$("#column-1").html(data);
});
});
});
And the way that returns null values:
$(document).ready(function () {
$(".boxItem").change(function (event) {
var url = "/Search/GetBoxChangeInfo";
$.post(url, { json: #Html.Raw(Json.Encode(Model)) }, function (data) {
$("#column-1").html(data);
});
});
});
i need to use it the second way because I need to also pass parameters back about the selected value and ID, so it will look something like:
$(document).ready(function () {
$(".boxItem").change(function (event) {
var str = $(this).attr('id');
var num = $(this).val();
var url = "/Search/GetBoxChangeInfo";
$.post(url, { json: #Html.Raw(Json.Encode(Model)), id : str, selected : num }, function (data) {
$("#column-1").html(data);
});
});
});
My controller looks like this btw:
[HttpPost]
public ActionResult GetBoxChangeInfo(EventViewModel json)
{
//stuff
}
EDIT - as requested, here is EventViewModel structure
[JsonObject(MemberSerialization.OptIn)]
public class EventViewModel
{
public int EventNumber { get; set; }
public List<EventItemsViewModel> EventItems { get; set; }
public List<LocationViewModel> Locations { get; set; }
public int StartLocationID { get; set; }
public bool Outbound { get; set; }
public List<int> SelectedEvents { get; set; }
public List<DurationsViewModel> Durations { get; set; }
}
Anyone know why this might be happening? Is there a limit to home much can be sent to the controller this way - it is quite a complex viewmodel, so wondered if that could be someting to do with it.
Thanks
Like this:
$(document).ready(function () {
$('.boxItem').change(function (event) {
var str = $(this).attr('id');
var num = $(this).val();
var url = '#Url.Action("GetBoxChangeInfo", "Search")';
$.ajax({
url: url,
contentType: 'application/json',
data: JSON.stringify({
json: #Html.Raw(Json.Encode(Model)),
id: str,
selected: num
}),
success: function(data) {
$("#column-1").html(data);
}
});
});
});
Things to notice:
contentType: 'application/json'
JSON.stringify to convert the object into a JSON string
var url = '#Url.Action("GetBoxChangeInfo", "Search")'; to avoid hardcoding urls
Is there a limit to home much can be sent to the controller this way - it is quite a complex viewmodel, so wondered if that could be someting to do with it.
Yes there is and it's 1000 HTTP Collection keys and you can configure that yourself in the web.config. Try setting the value to 4000 first, then you can lower it a bit if you like. Try this:
<appSettings>
<add key="aspnet:MaxHttpCollectionKeys" value="4000" />
</appSettings>
Use this
http://api.jquery.com/jQuery.post/
$.ajax({
type: 'POST',
url: url,
data: data,
success: success,
dataType: dataType
});
, I mean not shorthand Axaj Call. You have options like "success", "error", "completed" and can isolate issue.
I encountered the same error on ASP.NET MVC. On your model, you put ConvertEmptyStringToNull = false on your model's property's attribute:
[DisplayFormat(ConvertEmptyStringToNull = false)]
E.g.
public class Person
{
[DisplayFormat(ConvertEmptyStringToNull = false)]
public string Lastname { get; set; }
[DisplayFormat(ConvertEmptyStringToNull = false)]
public string Firstname { get; set; }
[DisplayFormat(ConvertEmptyStringToNull = false)]
public string Middlename { get; set; }
}
I documented when I encountered the same thing at this post: http://www.ienablemuch.com/2011/08/empty-string-is-empty-string.html