EDIT: I am able to pass some plain data if I use type: 'GET' in the ajax call and [HttpGET] in the Controller.
However, complex datatypes like my Summary class is still not working and everything is either 0 or NULL.
I have the following class:
public class Summary
{
public int Total { get; set; }
public double Average { get; set; }
public int Issues { get; set; }
public int Fixed { get; set; }
public double FixedPercentage { get; set; }
public double TotalPercentage { get; set; }
public List<Issues> IssuesList { get; set; }
}
public class Issues
{
public string Name {get; set;}
public int Code {get; set;}
}
And the following Action on my Controller:
[HttpGet]
public IActionResult GetSummary(Summary summaryBySource)
{
Json(new
{
summary = "hi"
});
}
Lastly, this is the ajax call I am using to return the object to the Controller:
$.ajax({
type: 'GET',
dataType: 'json',
url: '/Summary/GetSummary/',
data: JSON.stringify(summaryBySource),
error: function (xhr) {
alert("Wrong");
},
success: function (result) {
alert("Yeah");
},
async: true,
processData: true
});
Once the ajax call gets called, it jumps into the controller function but all its properties are NULL. Why is that happening?
BTW: the variable summaryBySource is a global variable that is in the View at the moment that the ajax call is called and it contains the values that matches with the Summary object.
Also, I tried to do the same thing but instead of passing an object, just a dumb string and it also returns null...
Thanks!
EDIT: The content of summaryBySource is
It will be an Object type and...
Total: 0
Average: 0
Issues: 2
Fixed: 1
FixedPercentage: 50
TotalPercentage: 100
IssuesList: Array[1]
0: Object
Name: "Crash"
Code: 1001
Related
Background: I have a jQuery Kendo data grid where I am allowing users to do batch update functionality. I am attempting to call my controller through an AJAX call in jQuery. The issue I am facing is that my model never gets passed to the controller method. When my breakpoint hits on Controller it comes with count of 0 with MyModel items. Even though I can see my model in Fiddler body of request it actually never makes it to the controller. This issue doesn't come up when I hit the API directly through Fiddler even when I pass in the same model which the application generates. What am I missing ? I am leaning towards something wrong with my AJAX request.
Below is my controller code:
[HttpPost]
[Route("UpdateRequest")]
[ResponseType(typeof(List<MyModel>))]
public HttpResponseMessage UpdateRequest([FromBody] List<MyModel> items)
{
var p = new GridItemProcessor();
var r = p.UpdateRows(items);
return Request.CreateResponse(HttpStatusCode.OK, r);
}
Below is my ajax call code:
$.ajax({
type: "POST", async: false, url: baseAPIURL + "MrrRequest/UpdateRequest",
timeout: 15000,
dataType: 'json',
cache: false,
data: {
items: JSON.stringify(options.data.models)
},
success: function (result) {
options.success(result);
return true;
},
complete: function (data) {
$("#myGrid").data("kendoGrid").dataSource.read();
},
error: function (jqXHR, textStatus, errorThrown) {
alert(textStatus);
options.error();
}
});
Below is how my json request looks like
[
{
"RequestId": 40,
"beneClaimId": 32,
"claimId": "20211308068186",
"lineCnt": "1",
"medRecRequested": true,
"eobChk": true,
"clmChk": true,
"dateReceived": null,
"MedRecRcvd": {
"MedRecRcvdId": "I",
"MedRecRcvdName": "Incomplete"
}
}
]
Below is what MyModel looks like
public class MyModel
{
public int RequestId { get; set; }
public int beneClaimId { get; set; }
public string claimId { get; set; }
public string lineCnt { get; set; }
public bool? medRecRequested { get; set; }
public bool? eobChk { get; set; }
public bool? clmChk { get; set; }
public string dateReceived { get; set; }
public ViewModel.MedRecRcvd MedRecRcvd { get; set; } = new MedRecRcvd();
}
public class MedRecRcvd
{
public string MedRecRcvdId { get; set; }
public string MedRecRcvdName { get; set; }
}
Your controller expects a collection of MyModel. Therefore you need to post an array of items. By using stringify you are posting a single string. As a test, if you changed your controller to accept 'string items' you should get a value in the controller.
Assuming your options.data.models is an array, you would post:
items: options.data.models
The properties on each item in that array need to match those on MyModel on the server. If that is the case, your posted data should materialise in the controller.
I have a strange problem. I have a C# data structure with two classes:
public class AddQuestionModel2
{
public int? QuestionID { get; set; }
public string QuestionString { get; set; }
public int? TrueAnswer { get; set; }
public QuestionType Type { get; set; }
public IEnumerable<AddQuestionModelAnswer> Answers { get; set; }
}
public class AddQuestionModelAnswer
{
public int? ID { get; set; }
public string AnswerString { get; set; }
public bool? IsRight { get; set; }
public int? Order { get; set; }
}
public enum QuestionType
{
SingleSelect,
MultiSelect,
OrderAnswers,
FillingGap,
ExampleRequired,
TrueOrFalse
}
The javascript generates the javascript object (which looks fine for the data structure) and JSON.stringify translates to the following json string:
{"QuestionString":"<p>Question 1</p>","TrueAnswer":"0","Type":"0","Answers":[{"AnswerString":"<p>Answer 1</p>","IsRight":"0"},{"AnswerString":"<p>Answer 2</p>","IsRight":"0"},{"AnswerString":"<p>Answer 3</p>","IsRight":"0"},{"AnswerString":"<p>Answer 4</p>","IsRight":"0"}]}
The json data is sent by the following jquery command:
$.ajax({
url: "/Questions/Add",
method: "POST",
async: true,
dataType: "json",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
success: function (e) {
if (e.Success) {
document.location = "/Questions";
}
},
error: function (e) {
var i;
for (i in e) {
console.log(e[i]);
}
}
});
On the C# side, I have the following method to receive the post data:
[HttpPost]
public async Task<string> Add([FromBody] AddQuestionModel2 q)
{
var ctx = this.HttpContext;
JsonResultModel res = new JsonResultModel();
}
The parameter "q" is always null. If I expand ctx (HttpContext), the Request.Form data is threw System.InvalidOperationException.
Does any if you have any idea what could be wrong?
The biggest problem is that I am unable to debug what is happening within HttpContext and why it is throwing exception.
Thanks in advance!
Gabor
In you ajax code try data:data, instead of data: JSON.stringify(data). The JSON.stringify() method converts a JavaScript object or value to a JSON string, but ajax data need JavaScript object. Another things to try instead of 0 or 1 use "true" or "false" in your bool fields.
In the postman everything works.
This is my class ARecipe :
public class ARecipe
{
public string picture { get; set; }
public string title { get; set; }
public int cookingTime { get; set; }
public int preparationTime { get; set; }
public string IngredientList { get; set; }
public string ingredientsDescription { get; set; }
public int nbPersons { get; set; }
public string Category { get; set; }
public string difficulty { get; set; }
public double nbStars { get; set; }
}
My Ajax call :
var dico = {
picture: $("#fakeInput").val(),
title : $("#title").val(),
cookingTime : $("#cookingTime").val(),
preparationTime : $("#preparationTime").val(),
IngredientList : $("#ingredientListArea").val(),
ingredientsDescription : $("#preparationArea").val(),
nbPersons : parseInt($("#select-nb-Persons").val()),
Category : $("#select-category").val(),
difficulty: $("#select-difficulty").val(),
nbStars : 4
};
$.ajax({
url: "/AddRecipe/TempData",
type: 'POST',
success: function (e) {
//success event
},
///Form data
data: JSON.stringify(dico),
///Options to tell JQuery not to process data or worry about content-type
cache: false,
contentType: false,
processData: false
});
And the method receiving the datas :
[HttpPost]
public ActionResult TempData(ARecipe recipe) {
return Json("");
}
My Ajax call well go to the TempData method but when I analyse the parameter 'recipe' with the debugger, I notice that all the fields are 'null'.
Why ?
Do you have a solution ?
Thank you
You are sending the data as JSON, but the server expects is as regular POST data. Just let the ajax method turn it into a regular POST request instead of forcing it into JSON:
///Form data
data: dico,
Just Correct these issues :
$.ajax({
url: "/AddRecipe/TempData",
type: 'POST',
dataType: 'json',
contentType: 'application/json',
success: function (e) {
//success event
},
///Form data
data: JSON.stringify(dico),
///Options to tell JQuery not to process data or worry about content-type
cache: false,
});
[HttpPost]
public JsonResult TempData(ARecipe recipe) {
return Json("");
}
I'm facing a strange issue when passing the following:
queueNotificationData = {
StartDate: that.batchData.StartDate.valueOf(),
StartTime: that.batchData.StartTime.valueOf(),
EndDate: that.batchData.EndDate.valueOf(),
EndTime: that.batchData.EndTime.valueOf(),
ETR: that.batchData.ETR.valueOf(),
PTW: that.batchData.PTW.valueOf(),
SelectedTemplate: that.batchData.SelectedTemplate.valueOf(),
IncidentFlag: that.batchData.IncidentFlag.valueOf(),
IncidentNumber: that.batchData.IncidentNumber.valueOf(),
SendToSubscriber: that.batchData.SendToSubscriber.valueOf(),
SendToCustomer: that.batchData.SendToCustomer.valueOf(),
SendToSMC: that.batchData.SendToSMC.valueOf(),
BatchServiceIds: that.serviceIds,
DescriptionOfWorks: that.batchData.DescriptionOfWorks.valueOf(),
AffectedCustomerVOs: that.customerVOs
}
The issue is with the AffectedCustomerVOs parameter - this is retrieved from an earlier call and is passed through a series of widgets (it's part of a pretty long wizard form)
This is the code that calls the c# method to actually do the processing:
this.options.sendRequest({
url: this.options.dataUrl,
data: queueNotificationData,
cache: false,
dataType: 'json',
success: function (data) {
that.data = data;
that._showSavedMessage();
},
error: function () {
that._showErrorMessage();
}
});
and here is the c# method:
[HttpPost]
[Authorize]
[ValidateInput(false)]
public JsonResult QueueNotificationBatch(QueueNotificationInputModel param)
{
//do some work - code not included
}
where QueueNotificationInputModel is
public class QueueNotificationInputModel
{
public string BatchServiceIds { get; set; }
public List<CustomerVO> AffectedCustomerVOs { get; set; }
public string StartDate { get; set; }
public string StartTime { get; set; }
public string EndDate { get; set; }
public string EndTime { get; set; }
public string ETR { get; set; }
public string PTW { get; set; }
public string SelectedTemplate { get; set; }
public string IncidentFlag { get; set; }
public string IncidentNumber { get; set; }
public bool SendToSubscriber { get; set; }
public bool SendToCustomer { get; set; }
public bool SendToSMC { get; set; }
public string DescriptionOfWorks { get; set; }
public QueueNotificationInputModel()
{
AffectedCustomerVOs = new List<CustomerVO>();
}
}
Now - all this code seems to work fine - the C# method is successfully called and the values passed in are good except for AffectedCustomerVOs. The list has 3 items in it (this is correct) but the items within the list have no values - all nulls/0's. If I put alert(that.customerVOs[0]['Email']); immediately before creating the queueNotificationData object, it correctly displays "test#test.com" but this value never makes it into the c# method.
I assume it's some sort of serialization problem but I can't figure out where? Help would be much appreciated
Try sending this complex object as JSON serialized:
this.options.sendRequest({
url: this.options.dataUrl,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(queueNotificationData),
cache: false,
dataType: 'json',
success: function (data) {
that.data = data;
that._showSavedMessage();
},
error: function () {
that._showErrorMessage();
}
});
The JSON.stringify method shown here 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.
I am trying to get model binding with MVC3 and JSON working but I have had no luck... No matter what I do I seem to be getting a null model on the server.
Method Signature:
public ActionResult FilterReports(DealSummaryComparisonViewModel model)
Javascript UPDATED:
<script type="text/javascript" language="javascript">
$(document).ready(function () {
$('#filter-reports').click(filterReports);
});
function filterReports() {
var filters = {
SelectedRtoId: $('#SelectedRtoId').val(),
SelectedPricingPointId: $('#SelectedPricingPointId').val(),
SelectedLoadTypeId: $('#SelectedLoadTypeId').val(),
SelectedBlockId: $('#SelectedBlockId').val(),
SelectedRevisionStatusId: $('#SelectedRevisionStatusId').val()
}
var dealSummaries = { SelectedItemIds: $('#SelectedItemIds').val() }
var model = { ReportingFilters: filters, DealSummaries: dealSummaries }
$('#selected-items select option').attr("selected", "selected");
$.ajax({
url: '#Url.Action("FilterReports")',
data: model,
contentType: 'application/json',
dataType: 'json',
success: function (data) {
alert(data);
}
});
}
</script>
Models:
public class DealSummaryComparisonViewModel
{
public ReportingFiltersViewModel ReportingFilters { get; set; }
public LadderListViewModel DealSummaries { get; set; }
}
public class LadderListViewModel
{
public MultiSelectList AvailableItems { get; set; }
public int[] SelectedItemIds { get; set; }
public MultiSelectList SelectedItems { get; set; }
}
public class ReportingFiltersViewModel
{
public int? SelectedRtoId { get; set; }
public ICollection<Rto> Rtos { get; set; }
public int? SelectedPricingPointId { get; set; }
public ICollection<PricingPoint> PricingPoints { get; set; }
public int? SelectedLoadTypeId { get; set; }
public ICollection<LoadType> LoadTypes { get; set; }
public int? SelectedBlockId { get; set; }
public ICollection<Block> Blocks { get; set; }
public int? SelectedRevisionStatusId { get; set; }
public ICollection<RevisionStatus> RevisionStatuses { get; set; }
public bool? DealStatus { get; set; }
}
The model looks fine on the client side:
{"ReportingFilters":{
"SelectedRtoId":"5",
"SelectedPricingPointId":"20",
"SelectedLoadTypeId":"55",
"SelectedBlockId":"21",
"SelectedRevisionStatusId":"11"
},"DealSummaries":{
"SelectedItemIds":["21","22","23","24","25"]
}}
So why am I getting nothing back on the controller? This has been giving me trouble for the past two days so please help! Thanks!!
UPDATE
I've updated my javascript section to what I am currently using. This section now returns the model to the controller with the ReportingFilers and DealSummaries objects, but all values within are null.
Does it possibly have something to do with the values being strings? If so, how can I fix this?
Change your $.getJSON line to:
$.ajax({
url: '#Url.Action("FilterReports")',
data: JSON.stringify(viewModel),
contentType: 'application/json',
dataType: 'json',
success: function (data) { alert(data); }
});
This way MVC knows that it is receiving JSON and will bind it to your model correctly.
Here's a few different things you could try:
Apparently you shouldn't use nullable properties in your objects if you want to use the DefaultModelBinder: ASP.NET MVC3 JSON Model-binding with nested class. So you could try making your ints not nullable or if that's not an option, implement IModelBinder yourself?
Have you marked your classes with the SerializableAttribute?
Try setting the type parameter in the ajax method to 'POST' - it will be using 'GET' by default.. type: 'POST'
Try explicitly setting the contentType parameter in the ajax method to this instead... contentType: 'application/json; charset=utf-8'
And finally, are you definitely using MVC 3, not MVC 2? I ask because MVC 3 has the JsonValueProviderFactory baked into the framework where as MVC 2 didn't so if you were using MVC 2 that might explain the problem you're having...
Ok, replace:
{ model: JSON.stringify(viewModel) }
with
{ model: viewModel }
You're mixing objects with JSON strings, so jQuery will JSON.stringify the entire object. Which will double encode viewModel.
here is what I would suggest, in your controllers action method should look as follows:
public JsonResult FilterAction(string model)
{
var viewModel=new JavaScriptSerializer().Deserialize<DealSummaryComparisonViewModel>(model);
}
Also make sure your request is reaching the right action and look at Firebug for the same.
Try this:
var filters = new Object();
filters.SelectedRtoId = $('#SelectedRtoId').val();
filters.SelectedPricingPointId = $('#SelectedPricingPointId').val();
filters.SelectedLoadTypeId = $('#SelectedLoadTypeId').val();
filters.SelectedBlockId = $('#SelectedBlockId').val();
filters.SelectedRevisionStatusId = $('#SelectedRevisionStatusId').val();
var dealSummaries = new Object();
dealSummarties.SelectedItemIds = $('#SelectedItemIds').val();
var viewModel = new Object();
viewModel.ReportingFilters = filters;
viewModel.DealSummaries = dealSummaries;
$('#selected-items select option').attr("selected", "selected");
$.getJSON('#Url.Action("FilterReports")', { model: JSON.stringify(viewModel) }, function (data) {
alert(data);
});