MVC JSON object with array not set properly - c#

I am making a tool in which one can get a Quotation throw javascript and then send himself that quotation. The making of the quotation is going fine but when sending the email, the quotation data is corrupt.
The data in the Quotation object is fine except for the Options array. When sending 3 array items the Options array holds 3 items except for their names are null and the price is 0.
The quotation is send to ASP.NET MVC 3 using jQuery.post.
Quotation object in C# looks like:
public class Quotation
{
public string Email { get; set; }
public string Product { get; set; }
public int Amount { get; set; }
public decimal BasePrice { get; set; }
public decimal SendPrice { get; set; }
public Option[] Options { get; set; }
public decimal Discount { get; set; }
public decimal SubTotal { get; set; }
public decimal TotalPrice { get; set; }
}
public class Option
{
public string Name { get; set; }
public decimal Price { get; set; }
}
The Action Method looks like:
[HttpPost]
public JsonResult Offerte(Models.Quotation quotation)
{
//
}
The jQuery looks like:
$.post(baseUrl + "/api/Offerte/", jsonContent, function (data) {
alert(data.Message);
});
The jsonContent object looks like:
{
"Options":[
{
"Name":"Extra pagina's (16)",
"Price":40
},
{
"Name":"Papier Keuze",
"Price":30
},
{
"Name":"Omslag",
"Price":29.950000000000003
}
],
"Amount":"5",
"BasePrice":99.96000000000001,
"SubTotal":199.91000000000003,
"SendPrice":0,
"Discount":19.991,
"TotalPrice":179.91900000000004,
"Email":"someone#example.com"
}
Does anyone know why the array is not set properly?
EDIT
If I add this debug code to the controller:
using (var writer = System.IO.File.CreateText(Server.MapPath("~/App_Data/debug.txt")))
{
writer.AutoFlush = true;
foreach (var key in Request.Form.AllKeys)
{
writer.WriteLine(key + ": " + Request.Form[key]);
}
}
Options[0][Name]: Extra pagina's (52)
Options[0][Price]: 156
Options[1][Name]: Papier Keuze
Options[1][Price]: 68.4
Options[2][Name]: Omslag
Options[2][Price]: 41.94
Amount: 6
BasePrice: 149.91899999999998
SubTotal: 416.25899999999996
SendPrice: 0
Discount: 45.78848999999999
TotalPrice: 370.47051
Email: someone#example.com
This means that the data does get to the controller but the Options still doesn't get set right. And I don't want an easy fix that I parse it myself afterwards, I want to know the correct way to handle it so MVC will take care of it.

If you want to send JSON data to an ASP.NET MVC controller action and you want the model binding work currently (e.g. binding collections on your model) you need to specify the contentType as "aplication/json".
Because with the $.post you are not able to specify the contentType you need to use $.ajax and you also need to JSON.stringify your data:
$.ajax({
url: baseUrl + "/api/Offerte/",
type: 'POST',
data: JSON.stringify(jsonContent),
contentType: "application/json",
success: function (data) {
alert(data.Message);
}
});

Related

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

JsonConvert.DeserializeObject<T>(value) does not deserialize the object assigned

I have created a page with a KnockoutJS viewmodel. I want to post the Data to my Server using Web API.
I use this AJAX post:
$.ajax({
url: "/api/blogpost",
contenttype: "application/x-www-form-urlencoded",
data: '=' + encodeURIComponent(ko.toJSON(self.Blog)),
type: "POST",
dataType: "JSON",
timeout: 10000,
success: function (Result) {
},
error: function (xhr, status) {
alert(status + " - " + xhr.responseText);
}
});
To send the JSON data to my Web API method.
This is the JSON that is sent to the server:
{
"BlogTitle": "Sample Post",
"BlogHTML": "<p><strong>Sample JSON Blog Post</strong></p>\n\n<h1><strong>It never works :( </strong></h1>\n",
"BlogThumbnail": "http://mysystemURL/SamplePost/What.jpg",
"BlogSummary": "This is a sample post",
"BlogFQURL": "Sample_Post",
"BlogTags": [
"json",
"devlopment",
"newtag",
""
],
"BlogCategory": 1
}
My WEB API method received the JSON data correctly. The RAW string value looks like this:
"{\"BlogTitle\":\"Sample Post\",\"BlogHTML\":\"<p><strong>Sample JSON Blog Post</strong></p>\\n\\n<h1><strong>It never Works :(</strong></h1>\\n\",\"BlogThumbnail\":\"http://mysystemURL/SamplePost/What.jpg\",\"BlogSummary\":\"This is a sample post\",\"BlogFQURL\":\"Sample_Post\",\"BlogTags\":\"[\\\"json\\\",\\\"devlopment\\\",\\\"newtag\\\",\\\"\\\"]\",\"BlogCategory\":1}"
when I use the JSON visulizer on my data I get this:
I use this BlogPost vari = JsonConvert.DeserializeObject<BlogPost>(value); to deserialize my object but everything stays null
My BlogPost Object looks like this:
public class BlogPost
{
public int BlogPostID { get; set; }
public string BlogPostTitle { get; set; }
public string BlogPostHTML { get; set; }
public string BlogPostThumbnailURL { get; set; }
public string BlogPostSummary { get; set; }
public string BlogPostFQURL { get; set; }
public int BlogPostCategory { get; set; }
public List<TagDTO> BlogPostTags { get; set; }
}
I am really stumped.. Any help would be greatly appreciated!
Your property names don't match. The C# object's properties are BlogPost* and the JSON has Blog*, without the Post.
Correct the names either on the Javascript or on the C# side or use the JsonProperty attribute to specify the name of the serialized property.

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