Using a javascript object in C# - c#

I have a javascript object and would like to use it in my C# function but I am unsure how I can use this object.
Javascript:
$.ajax({
data: data.model,
cache: false,
type: 'post',
url: 'Respondents/DownloadCSV',
});
Notice the data.model javascript object looks like so (taken from console.log):
[Object, Object, Object, Object, Object]
0: Object
1: Object
2: Object
3: Object
4: Object
Inside the 0:Object
Class: "respondent clickable gradeA"
Data: Object
Age: ""
City: ""
Email: null
Ethnicity: ""
Gender: ""
Id: 260619
LastActionDate: "<span class="dn">20131008175555</span>10/8 5:55 PM"
LastRecruiter: "Ben Miles"
Name: "Jerry Keys"
OwningRecruiter: "Ben Miles"
RecruitingGroup: "Competitive Users"
Source: "<span style="display:none;" >Database</span><i class="tipN icon-tasks" original-title="Database"></i>"
State: ""
Status: "<span style="display:none;" >Completed</span><i class="tipN icon-check" original-title="Completed"></i>"
class: "respondent clickable gradeA"
created: 1386790341009
url: "/Projects/644/Respondents/260619/Overview"
I am not sure what my C# method would have to look like? I would expect something like?
public ActionResult DownloadCSV(object model)
{
}
All I want to do is use the data from JavaScript in a controller method.

ASP.NET MVC provides automatic model binding from JSON notation to your Actions as long as your model matches the JSON in its format.
So, as an example, if you are posting some information about a person, your JSON would look like this...
{ "FirstName": "John", "LastName": "Doe" }
This can, of course, get considerably more complicated, but, I'm just doing this for an example.
Now, in your Action, you want to create an POCO that matches what you expect from your JavaScript so it can bind correctly. This object would look like this:
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
}
Then, in your action, you do...
public class MyController {
[HttpPost]
public ActionResult MyAction(Person model) {
// Do what you need to here.
}
}
As long as your JSON aligns with the model, the binding will happen automatically.
Note, that if you need to convert your JavaScript object to JSON, then you can use the JSON.stringify(your_object) to do so and pass that to the data parameter of the ajax call.

Try this:
$.ajax({
data: JSON.stringify(data.model),
cache: false,
type: 'POST',
url: 'Respondents/DownloadCSV',
dataType: 'json',
contentType: 'application/json; charset=utf-8'
});
This should work with any object of any arbitrary depth.

You could create a class with properties that your json document has:
public class MyModel
{
//properties
}
Then, change your Action to take a list of these:
public ActionResult DownloadCSV(IEnumerable<MyModel> model)
{
}
The serializer will take care of mapping, but there are a few concerns:
LastActionDate: "2013100817555510/8 5:55 PM"
You'd want to pass in the actual date, not HTML representation, unless you want all your classes properties to be string

Related

Serializing form data into a model for an Ajax POST

I have an MVC web application, with this model
public class PersonViewModel
{
public Guid SchoolId { get; set; }
public string Name { get; set; }
}
public class StudentViewModel : PersonViewModel
{
}
I have this controller method to take a StudentViewModel and create a Student in my database:
[HttpPost]
public async Task<IActionResult> CreateStudent(StudentViewModel viewModel)
{
// ... do stuff
}
I'm doing a lot of dynamic UI stuff with my form, and I might be posting to different endpoints with different values, so I decided to just submit the form using javascript and decide where I'm posting to based on some conditionals.
So that's basically the reason I'm not going the normal route with the strongly typed helper methods - this is what I have in my view:
<form id="form">
<input name="SchoolId" value="#Model.Id" type="hidden" />
<input name="Name" type="text" />
<button type="submit">Create</button>
</form>
<script>
$(document).ready(function () {
$('#form').on('submit', function (e) {
e.preventDefault();
var formData = $('#form').serialize()
console.log(formData);
$.ajax({
url: '/CreateStudent',
type: "POST",
data: formData,
contentType: "application/json"
});
});
});
</script>
I can see in my console log that the form data is serialized correctly, and it hits my controller method. But the view model parameter doesn't have the values that I passed to it.
I've tried setting the form data this way:
var formData = JSON.stringify($('#form').serializeArray());
I even tried just hardcoding the values:
var formData = '{"SchoolId":"c65fc8ad-7ad2-e811-b37f-9cb6d0b709c2","Name":"Testing"}';
But no matter what I try, the view model values don't get set.
Am I formatting the form data wrong? Or is there a different way completely that I need to do this?
When you use .serialize(), it generates the data in a 'query string' format - i.e. SchoolId=someValue&Name=AnotherValue, which needs to be sent using the default contentType which is 'application/x-www-form-urlencoded; charset=UTF-8', not as JSON.
Either remove the contentType option or specify contentType: 'application/x-www-form-urlencoded; charset=UTF-8'
$('#form').on('submit', function (e) {
e.preventDefault();
var formData = $('#form').serialize()
$.ajax({
url: '#Url.Action("CreateStudent")', //recommended
type: "POST",
data: formData,
contentType: 'application/x-www-form-urlencoded; charset=UTF-8' // optional
});
});
Note that if you were to use contentType: "application/json", then you would generate the data using (assumes you give the inputs the appropriate id attribute)
var formData = JSON.stringify({
SchoolId: $('#SchoolId').val(),
Name: $('#Name').val(),
})

POST data is null with ASP.NET API Controller

I am trying to migrate to an ASP.NET 6 API controller and my POST data from my JS function is showing as null.
I have the following json request:
// searchTerms is an array with 2 properties, Value and Type
$.ajax({
type: 'Post',
contentType: 'application/json',
dataType: "json",
data: JSON.stringify({
searchTerms
})
if I POST this to an ASP.NET 6 MVC controller:
public ActionResult Search(List<SearchTerm> searchTerms)
Then my searchTerms list is properly populated.
If I POST to an API Controller
[System.Web.Http.HttpPost]
[System.Web.Http.Route("api/search")]
public IHttpActionResult Search([FromBody] List<SearchTerm> searchTerms)
Then searchTerms is null.
I have tried to change the contentType, dataType, remove the stringify function to no avail.
I have tried to changed the signature to
public IHttpActionResult Search([FromBody] dynamic value)
And see the following, so obviously I'm not binding properly?
Here is my SearchTerm model:
public class SearchTerm
{
public string Value { get; set; }
public string Type { get; set; }
}
Instead of:
data: JSON.stringify({
searchTerms
})
Change your $.ajax call to use just:
data: JSON.stringify(searchTerms)
You are sending JSON that looks something like:
{
"seachTerms": [
...
]
}
With the change I suggested, this would just be a simple JSON array, which should work in your example.

.NET MVC jQuery AJAX - JSON object as parameter not serializing values

I'm trying to figure out how to simply pass a JSON object into a controller method param. I'll often use JSON.serialize() when posting forms and the serialization to C# is automatic. However, I'm struggling to get this to work using GET while trying to load a partial.
I built a small sample project as a basic simulation of what I need, which is a controller method that accepts an int param and a separate model class, which I'd like to pass in as JSON. The partial html response is loaded into a div.
The view:
<div class="row">
Loading a partial via Ajax, passing a JSON object as a param!
</div>
<div class="row">
<div id="peoplePartial"></div>
</div>
#section Scripts {
<script>
$(function() {
var id = 1;
var person = {
Name: "Homer Simpson",
Age: 45
};
load(id, person);
});
function load(id, person) {
$.ajax({
cache: false,
type: "GET",
dataType: "html",
url: '/Home/PeoplePartial',
data: {
id: id,
person: JSON.stringify(person)
}
}).done(function(data) {
$("#peoplePartial").html(data);
}).fail(function(data) {
console.log(data.responseText);
});
}
</script>
}
The partial:
#model MVCLearning.Models.PeoplePartialModel
<div>
<span>Person found! Name is #Model.Person.Name</span>
</div>
The partial ViewModel:
public class PeoplePartialModel {
public int Id { get; set; }
public PersonModel Person { get; set; }
}
The data model/entity I'm trying to serialize:
public class PersonModel {
public string Name { get; set; }
public int Age { get; set; }
}
And finally, the controller:
public class HomeController : Controller {
public ActionResult Index() {
return View();
}
public ActionResult PeoplePartial(int id, PersonModel person) {
if (person != null) {
var model = new PeoplePartialModel {
Id = id,
Person = person
};
return PartialView("_People", model);
} else {
throw new System.Exception("An Error Has occoured");
}
}
}
The "id" param always works, of course, but the PeopleModel param is always null when using JSON.stringify(). I would have expected it to serialize to the model and contain the JSON values I passed in from the JS in the view. I can fix this by not using JSON.stringify() but then the values are always ignored e.g. always passed in as Name: null, Age: 0. I just can't seem to pass values like this.
I've tried changing the ajax call to POST but it changes nothing. I've tried setting the contentType to html and json, neither change anything.
Thanks in advance.
I got it. Here's the magic combination of properties:
function load(id, person) {
$.ajax({
type: "POST",
dataType: "html",
url: "/Home/PeoplePartial",
data: {
id: id,
person: person
}
}).done(function(data) {
$("#peoplePartial").html(data);
}).fail(function(data) {
console.log(data.responseText);
});
}
I think one of the variations I had tried was POST with the contentType set. That throws an error saying both controller method params are null, strangely. I also could have omitted dataType on this and it works. I could not get any variation of GET to work, even though GET is what I'm trying to do. I'd really like to know why this is the case.

Array to mvc controller with ajax

I'm trying to get some data (multidimensional array) to my GET controller (for display in a modal/dialog box) from a list (the user checks some values and then gets sent to a modal/dialog box that should display the chosen values):
$('input:checkbox').each(function () {
if ($(this).is(':checked')) {
var prop= [];
prop['Name'] = "TEST";
prop['Id'] = "123"
data.push(prop);
}
});
When I log this (above) data, it looks fine. Then I use it the ajax call:
$.ajax({
type: "GET",
url: url,
data: JSON.stringify({ data }),
contentType: "application/json; charset=utf-8",
success: function () {
alert("OK");
}
});
I've a Model for using the data in the action (and the partial view):
public class MyClass
{
public string Name { get; set; }
public string Id { get; set; }
}
This is my action:
public ActionResult Merge(MyClass[] theData)
{
...
}
But in the action the 'theData' is always null. If I use 'POST' in the ajax, the POST action gets called, and I don't want to do that in this step. I want to use the POST action after, when the user have made some modifications (eg. Title change) and then saves. THEN I do a POST and saves the new data.
Please try this
$('input:checkbox').each(function () {
if ($(this).is(':checked')) {
var prop= {};
prop.Name = "TEST";
prop.Id = "123"
data.push(prop);
}
});
The parameter in your Merge() method is MyClass[] theData which means you need to send an array of objects, not an array of arrays. Start by changing the script to generate the data to
var data = [];
$('input:checkbox').each(function () {
if ($(this).is(':checked')) {
data.push({ Name: 'TEST', Id: '123' });
}
});
Next, you need to change the method to a [HttpPost] (rename it if necessary to avoid any conflict with any existing [HttpPost]public ActionResult Merge( .. ) method).
Then you need to change the type to "Post" and stringify the data with the name of the methods parameter before sending it
$.ajax({
type: 'Post', // change this
url: url,
data: JSON.stringify({ theData: data }), // change this
contentType: 'application/json; charset=utf-8',
success: function () {
alert("OK");
}
});
Side note: If you did want to do this to a [HttpGet] method, then it would be be necessary to send the data as .../Merge?[0].Name=TEST&[0].Id=123&[1].Name=TEST&[1].Id=123 etc (i.e. with indexers), however you should not generally be sending collections of objects to a GET method. Apart from the ugly query string, you could exceed the query string limit and throw an exception.
You're sending your data as a string. Don't use JSON.stringify
Change
data: JSON.stringify({ data })
to
data: data

Similar property names in ViewModel not binding in controller action method

Recently we updated our application from MVC3 to MVC4. In MVC4 we have discovered that having property names like Studio and StudioExecutive in our ViewModel will cause problems when posting. In the controller method we will always get Studio = null when StudioExecutive is being populated.
Here is an example of our issue and hope there is an answer for this problem.
Data Classes:
public class TestContact
{
public List<TestContactItem> Studio { get; set; }
public List<TestContactItem> StudioExecutive { get; set; }
public TestContact()
{
Studio = new List<TestContactItem>();
StudioExecutive = new List<TestContactItem>();
}
}
public class TestContactItem
{
public int Id { get; set; }
public string Name { get; set; }
}
Controller Methods:
public ActionResult TestContactView()
{
var vm = new TestContact();
vm.Studio.Add(new TestContactItem(){Id=1, Name = "Studio Contact ID=1"});
vm.StudioExecutive.Add(new TestContactItem() { Id = 2, Name = "Studio Exec Contact ID=2" });
return View(vm);
}
[HttpPost]
public ActionResult SaveTestContact(TestContact model)
{
return Content("success");
}
View / JavaScript with Ajax POST:
#using System.Web.Script.Serialization
#model TestContact
<button type="button" onclick="SaveTestContact();">Click Here to Post</button>
<script type="text/javascript">
$(document).ready(function() {
globalTestModel = #Html.Raw(new JavaScriptSerializer().Serialize(Model));
});
function SaveTestContact() {
// passing additional studio & studio executive parameter to controller because it was not mapping correctly to the server side viewmodel without it
$.ajax({
type: "POST",
url: "/Test/SaveTestContact",
data: JSON.stringify(globalTestModel),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (msg) {
}
});
}
</script>
In this example we are populating our object with at least one Studio and one StudioExecutive and render the view. When the button in the view is clicked, we POST the same object to the controller method but the ViewModel is not binding correctly the Studio property is set to null.
*Unfortunately I'm not able to post images I have a screenshot of the object showing that the Studio count was 0 and the StudioExecutive count was 1
We did put a breakpoint before the POST to make sure the serialization on the JavaScript was correct and the object was populated.
We have concluded that this has to do with the naming convention of the 2 properties one being a substring of the other. Any one who has encounter the same problem and can point us on the right direction.
I know this is not the "complete answer" to the question but I feel that this will give additional insight to the issue, that (I hope) will eventually lead to the "complete solution".
Say we have a single item in each of Studio and StudioExecutive fields as shown in the example of the OP, and do the following in js:
globalTestModel = '#Html.Raw(new JavaScriptSerializer().Serialize(Model))';
$.ajax({
type: "POST",
url: "/Test/SaveTestContact",
data: JSON.stringify(globalTestModel),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (msg) {
}
});
The controller method will only receive StudioExecutive as already mentioned. Now if we do the same and build the object in js as shown below, we get the same result.
o = {
Studio: [{
Id: 1,
Name: 'Studio Contact ID=1',
}],
StudioExecutive: [{
Id: 2,
Name: 'Studio Exec Contact ID=2',
}]
};
$.ajax({
type: "POST",
url: "/Test/SaveTestContact",
data: JSON.stringify(o),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (msg) {
}
});
Now here comes the interesting part. If we add another item to the Studio field and post the same way we will get the same result.
// Do this in the controller and do the same ajax post
public ActionResult TestContactView()
{
var vm = new TestContact();
vm.Studio.Add(new TestContactItem(){Id=1, Name = "Studio Contact ID=1"});
vm.Studio.Add(new TestContactItem(){Id=3, Name = "Studio Contact ID=3"});
vm.StudioExecutive.Add(new TestContactItem() { Id = 2, Name = "Studio Exec Contact ID=2" });
return View(vm);
}
But if we will build the object in js as shown below the controller will receive both the Studio, with 2 items, and the StudioExecutive, with one item.
o = {
Studio: [{
Id: 1,
Name: 'Studio Contact ID=1',
},
{
Id: 2,
Name: 'Studio Contact ID=2',
}],
StudioExecutive: [{
Id: 2,
Name: 'Studio Exec Contact ID=2',
}]
};
// then do the ajax post
So what have we learned
This tells us two things:
There is something wrong with the default model binder in that it cannot bind two, or more, fields that starts with the same name
JSON.stringify can also NOT do it if there is only one item, but it can do it if there are more than one item in the field that has the shortest name (e.g. Studio)

Categories

Resources