MVC3 & JSON.stringify() ModelBinding returns null model - c#

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

Related

Ajax call data is not being passed to the controller during a POST

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.

JQUERY ajax posts JSON to C# MVC controller, but the incoming data is null

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.

Using AngularJS to post form data to a ViewModel that is defined within ASP.NET MVC application

I would like to collect some data using AngularJS and post it back to my ASP.NET WebAPI controller.
I have defined my business object like this (which just aims to record overall annual petrol consumption along with consumption every month):
public class PetrolViewModel
{
public double petrol_annual { get; set; }
public int petrol_measure { get; set; }
public List<Month> months { get; set; }
}
public class Month
{
public double jan { get; set; }
public double feb { get; set; }
}
In my Angular code I have:
var app = angular.module('petrol', []);
app.controller('PetrolController', function ($scope, $http) {
$scope.petrol = {};
$scope.petrol.months = {};
$scope.sendForm = function() {
$http({
method: 'Post',
url: 'api/values',
data: $scope.petrol
}).success(function (data, status, headers, config) {
console.log(data);
console.log(status);
console.log(headers);
}).error(function (data, status, headers, config) {
console.log(data);
console.log(status);
console.log(headers);
});
};
});
When I submit the form data and leave the WebApi controller to receive an anonymous object it seems to work and I get my form data:
But, if I change this and try to pass in the ViewModel I defined earlier I get a null object being passed in:
I want to take full advantage of the ASP.NET features to automatically map the matching names and deliver me a populated Object that I can then handle in my code. I don't want to have to map the anonymous object to the ViewModel.
So, the programming question is: How do I make sure my AngularJS object can be matched to a ViewModel?
In tutorials I've been watching this seems to "just work" for everyone else so they tend not to cover it in much detail.
Here is the JSON that is being sent up, according to Fiddler:
{"months":{"jan":"10","feb":"10","mar":"10","apr":"10","may":"10","jun":"10","jul":"10","aug":"10","sep":"5","oct":"5","nov":"20","dec":"10"},"petrol_annual":"120","petrol_measure":"1"}
I'm not sure why petrol_annual or petrol_measure aren't model binding correctly, but the List<Month> needs to be Month instead:
public class PetrolViewModel
{
public double petrol_annual { get; set; }
public int petrol_measure { get; set; }
public Month months { get; set; }
}
This is because months in the JSON is an object, not an array. It should match up with the Month class on the server. The Month class should also include entries for all months, but you may have just ommitted those for brevity in your OP.
Below works. Perfectly fine.
Code:
public class CatergoriesViewModel
{
public string OrderSelected { get; set; }
public string CatergoryName { get; set; }
}
var data = { catergoryName: "TestCat", orderSelected: "true" };
$http.post("Category", data)
.then(function (response) {
$scope.test = response.data;
}, function (error) {
$scope.test = error;
});

strange issue passing a JSON object to c# method (with a collection as a parameter (using JQuery Widgets)

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.

using json to object binding in asp.net mvc2

I am trying to bind a JSON stringified object to a model and few other strings in the controller and it is not working.
is it not possible,
$.ajax({
url: "/SrcManager/AddDataSource",
type: "POST",
data: JSON.stringify({
content: ct,
dataSourceName: $("#dataSrcName").val(),
parameters: parametersCollection,
sourceContentId: sourceContentId,
sourceId: null,
type: contType
}),
success: function (data) {
if (data.length > 1)
{
alert("DataSource Saved Successfully");
$("#dataSrcId").val(data);
}
}
});
and var parametersCollection = [];
function IPParameters(paramName, paramValue) {
this.ParamName = paramName;
this.ParamValue = paramValue; }
*** action method : public string AddDataSource(ContentModel scvm){.........}
Why does the above not work. Is this not supported or any mistake in the code, kindly suggest the right way.
In the ContentModel, i map the parameters to List<Parameters>.
I have added the JsonValueProviderFactory also in global.asax.
The C# model is :
public class SourceContentViewModel
{
public string sourceId { get; set; }
public string dataSourceName { get; set; }
public string sourceContentId { get; set; }
public string content { get; set; }
public string type { get; set; }
public List<Parameters> parameters { get; set; }
public SourceContentViewModel()
{
parameters = new List<Parameters>();
}
}
public class Parameters
{
public string ParamName { get; set; }
public string ParamValue { get; set; }
}
You can't send JSON to an ASP.NET MVC 2 application as there is no JSON provider factory out-of-the-box that will allow you to read the request. It is built in ASP.NET MVC 3. You may take a look at the following blog post and include the JsonValueProviderFactory discussed there. Then you will be able to send JSON requests to your ASP.NET MVC 2 controller actions after registering it:
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
}
Also notice the contentType: 'application/json; charset=utf-8' setting when sending the request which instructs the binder that you are sending a JSON request.

Categories

Resources