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

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.

Related

Pass a lot of parameters (ajax, asp.net)

I want to pass some parameters via ajax function. I was able to pass the string list or 2 parameters (int type). I'm having trouble passing a list and an int parameter. Ultimately, there may be even more parameters than two.
My example:
.cs file:
public string AddListElement(int secId, List<string> fieldsList)
{
//code...
return "a";
}
.cshtml file:
<script>
function AddElement(idSection) {
var stringArray = new Array();
stringArray[0] = "item1";
stringArray[1] = "item2";
stringArray[2] = "item3";
$.ajax({
type: "POST",
url: "/BK/User/AddListElement",
data: {
secId: idSection,
fieldsList: stringArray,
},
dataType: "json",
traditional: true,
}).fail(function () {
//code...
}).done(function (data) {
//code...
});
}
</script>
//other code...
<div class="form-group main-center2 col-8 mt-2">
<a class="btn btn-success btn btn-block" onclick="AddElement(#Model.Section[i].Id);" href="#">
Dodaj
</a>
</div>
In this case, idSec is well passed but the list is null. I was able to pass it well by passing the idSec in the Url and the list like this. But in my opinion it's not the best solution, especially if I want more parameters, e.g. 2 lists and 3 int parameters.
How can I pass multiple parameters like this? Assuming that the parameters are different: int, string, list.
I read similar topics but no way worked for me.
PS.
The best way to receive JSON content from body is define a model according to the attributes of JSON, like your situation, you can define this:
public class ReceiveData
{
public int secId { get; set; }
public List <string > fieldsList { get; set; }
}
And the controller:
public string AddListElement(ReceiveData data)
{
//code...
return "a";
}
But if you do not want to define a extra model, you can use a Dictionary<string, object> to hold all the data you want to receive from POST:
public string AddListElement(Dictionary<string, object> keyValuePairs)
{
//code...
return "a";
}
Only one parameter per action may be bound from body
Controller methods map a single parameter to the request body; you can use [FromBody] (a parameter attribute) to specify which one (see here):
When a parameter has [FromBody], Web API uses the Content-Type header to select a formatter. In this example, the content type is "application/json" and the request body is a raw JSON string (not a JSON object).
At most one parameter is allowed to read from the message body. So this will not work:
// Caution: Will not work!
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }
In your case, create a DTO that models the JSON object you send:
class ListElementDto {
public int SecId { get; set; }
public List<string> FieldsList { get; set; }
}
public string AddListElement([FromBody] ListElementDto model)
{
//code...
return "a";
}
Side-note: you will want to set the Content-Type header in your request to "application/json", and I also recommend running JSON.stringify on your data. Ajax dataType is for telling ajax what to expect as the server response.

[dotNET Core]Passing model to view -> bind checkbox with it's data in POST method form -> sending whole model to controller

I need some help. I am trying to pass ShowSeatsViewModel to Seats.cshtml bind it with passed view model's field and send it back with new values to controller.
ViewModel :
using System.Collections.Generic;
namespace theatre_dotNET.Models
{
public class SpectacleShowsViewModel : Spectacle
{
public List<Show> IncomingShows { get; set; }
public Show pickedShow { get; set; }
public int[] availableSeats { get; set; }
public int[] bookedSeats { get; set; }
public SpectacleShowsViewModel(Spectacle s, List<Show> incomingShows)
{
this.SpectacleId = s.SpectacleId;
this.Title = s.Title;
this.Description = s.Description;
this.Price = s.Price;
this.VideoLink = s.VideoLink;
this.Rating = s.Rating;
IncomingShows = incomingShows;
}
}
}
Two methods of controller :
[Authorize]
public IActionResult Seats(Show chosenShow)
{
int[] availableSeats = _context.Seats.Select(s => s.SeatId).ToArray();
int[] bookedSeats = _context.BookedSeats.Where(i => i.ShowId == chosenShow.ShowId).Select(s => s.SeatId).ToArray();
return View(new ShowSeatsViewModel(chosenShow, availableSeats, bookedSeats));
}
[Authorize]
[HttpPost]
public IActionResult Seats(ShowSeatsViewModel chosenShowSeatsViewModel)
{
return Content("Picked seats : "+chosenShowSeatsViewModel.PickedSeats);
}
View:
#model ShowSeatsViewModel
<h1>Chosen Spectacle : Model.SpectacleId</h1>
<form asp-controller="Booking" asp-action="Seats" method="post">
<div class="row">
#foreach(var seat in Model.AvailableSeats)
{
#if(Model.UnavailableSeats.Contains(#seat))
{
<div class="col">
#Html.CheckBoxFor(m=>m.PickedSeats[#seat-1])
#Html.LabelFor(m=>m.PickedSeats[#seat-1],#seat.ToString())
</div>
}
else
{
<div class="col">
#Html.CheckBoxFor(mdl => mdl.PickedSeats[#seat-1])
#Html.LabelFor(mdl => mdl.PickedSeats[#seat-1],#seat.ToString())
</div>
}
}
</div>
<button type="submit">Submit</button>
</form>
And an error - after choosing checkboxes and clicking submit button:
InvalidOperationException: Could not create an instance of type 'theatre_dotNET.Models.ShowSeatsViewModel'. Model bound complex types must not be abstract or value types and must have a parameterless constructor. Alternatively, give the 'chosenShowSeatsViewModel' parameter a non-null default value.
How could I send existing(passed from Controller) ViewModel via post method? Is it possible?
EDIT: I'm updating my answer.
In your case, you can't model bind to that Object without custom model binding.
It's a complex object that doesn't have a parameterless constructor.
You need to have all of the properties in the form to pass the entire model with. As you stated that's not what you want.
In your case a custom model binder is a complex implementation that you would have to do over and over throughout the app. I wouldn't recommend this approach.
On the client side I would use a library like JQUERY to perform the post for complex objects.
Here is an example.
Create a JS script to run these POST requests with complex objects with the following function.
Here is an example with JQuery
function ajaxRequest(httpVerb, url, model, onSuccess, onFail, onComplete) {
if (httpVerb === null || httpVerb.length === 0) httpVerb = "POST";
$.ajax({
url: url,
type: httpVerb,
cache: false,
traditional: true,
data: JSON.stringify(model),
dataType: "json",
contentType: 'application/json; charset=utf-8'
}).done(function (data) {
//onSuccess()...
}).fail(function (err) {
//onFail()...
}).always(function (data) {
//onComplete()...
});
}
Here is how you would call it
var model = #Html.Raw(Json.Encode(Model)); //this gets your view model and converts it to a JS object.
//Or you can take the time and create it manually
var model = {...}
//take the form values and replace the model properties as needed
// make sure to give your HTML elements in the forms ID attributes so you can select them.
model.PickedSeats = $('#myCheckboxById').is(':checked');
...
// do the same with the other form values
ajaxRequest("POST", "/Booking/Seats", model , null, null, null);
//the null values being passed in are the callback functions you would perform in the method signature. I just left them null to simplify things.

How return list object to show in view

I have controller where I use service. That service do some querys and return List like this:
Controller:
public ActionResult GetTareas(string tiporesponsable, int responsableID, int? cuadrillaID, int? sucursalID, int regionID, int solicitudID, string chkFinalizadas)
{
var consulta = ag.ConsultarAgenda(tiporesponsable, responsableID,
cuadrillaID, sucursalID, regionID, solicitudID, chkFinalizadas);
return View();
}
Now I want to get some value of that service (ag.ConsultarAgenda) for example: "SucursalCodigo" and receive into view into div like:
<div id="event_box" class="margin-bottom-10"></div>
Can anyone explain me how can I do it? Regards
Can I do sending Json? like:
return Json(consulta, JsonRequestBehavior.AllowGet);
but How can I receive specific object into view?
ASP.NET MVC offers us several options for passing data from controller to view upon request, one of them is ViewBag.
As of your example above you can do the following in the controller part:
public ActionResult GetTareas(string tiporesponsable, int responsableID, int? cuadrillaID, int? sucursalID, int regionID, int solicitudID, string chkFinalizadas)
{
ViewBag.ConsultarAgenda = ag.ConsultarAgenda(tiporesponsable, responsableID,
cuadrillaID, sucursalID, regionID, solicitudID, chkFinalizadas);
return View();
}
And in the view :
<div id="event_box" class="margin-bottom-10">#ViewBag.ConsultarAgenda</div>
The best practice to consume Json is via AJAX on the frontend(The View):
<script type="text/javascript">
$.ajax({
url: '#Url.Action("GetTareas", "ControllerName")',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data){
//consume the returned data here
$(".margin-bottom-10").html(data);
},
error: errorFunc});
</sript>
<div id="event_box" class="margin-bottom-10"></div>
A ViewBag should work:
#ViewBag.TexttoLargo
You may want to parse the ViewBag result as it it looks like it is terminated with a return.
As Mike McCaughan mentioned you should go throught some tutorials.
You have multiple options based on this
ViewBag
The ViewBag is a dynamic object that provides a convenient late-bound way to pass information to a view
#model Keyword
Strongly typed class.
example
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Movie movie = db.Movies.Find(id);
if (movie == null)
{
return HttpNotFound();
}
return View(movie);
}
then accessing model in view:

Populate DropDownList from Azure Database in MVC

I am still new to MVC and working my way around it. I need to get the "name" column of my district table into a dropdownlist to be able to pick from different Districts. The end game is that the user will pick a District from the dropdownlist and then be directed to a page where a list of schools(in a different table) will be shown with the selected district (i think that would be a query on the database using the value given from the dropdownlist). Basically what I have done so far is:
Create an MVC Application.
Create a Entity Framework Model.
Create an empty controller.
Create a view model(since every tutorial/ site answer has said to do
so)
Create a view.
I replicate step by step what these tutorials are telling me to do, but I get a different result. My dropdownlist gives me this outcome:
I need help sorting out what could be going wrong and why the data is not showing up in my dropdownlist.
Try I believe you are using the wrong SelectList constructor. Assuming you want the value of the drop down list to be the "leaID" property
#Html.DropDownList("myList", new SelectList(ViewBag.districts, "leaId", "name")
I would however, approach it another way which will keep it mostly strongly typed:
public class DistrictViewModel
{
public string SelectedDistrictId { get; set; }
public IEnumerable<SelectListItem> Districts { get; set; }
}
Action:
public ActionResult Index()
{
var viewModel = new DistrictViewModel()
{
Districts = new SelectList(db.Districts.ToList(), "leaID", "name")
}
return View(viewModel);
}
cshtml:
#model DistrictViewModel
#Html.DropDownListFor(m => m.SelectedDistrictId, Model.Districts)
Here is my answer to your comment using ajax
//Model
public class DistrictViewModel
{
public string name {get;set;}
public SelectList District {get;set;}
public int SelectedDistrict {get;set}
}
//Controller
public class DistrictController : Controller
{
KUDEREntities db = new KUDEREntities();
public ActionResult Index()
{
var model = new DistrictViewModel();
model.Districts = db.Districts.ToList();
model.SelectedDistrict=0;
return view(model);
}
[HttpPost]
public ActionResult Search(int id)
{
//do the search with the id of the selected district
var data = db.Districts.Where(m=>m.leaId = id).FirstorDefault();//this would return the whole object.
return Json(data, JsonRequestBehavior.AllowGet);
}
}
//Index View
#Model DistrictViewModel
<div>
//with this your selector would be "#SelectedDistrict"
#Html.DropDownListFor(model=>model.SelectedDistrict, new SelectList(Model.Districts,"leaId","name",Model.SelectedDistrict), new {#class=""})
//with this your selector would be "#myList"
//#Html.DropDownList("myList", new SelectList(ViewBag.districts, "leaId", "name", Model.SelectedDistrict)
</div>
<script>
$(document).ready(function(){
//when you want to search for the id selected, you just need to call the Search function below
function Search() {
//... now you have the value of the selecteditem
var parameters = { id: $("#SelectedDistrict").val() };
$.ajax({
type: 'post',
url: '#Url.Action("Search", "District")',
cache: false,
contentType: "application/json; charset=utf-8",
dataType: "html",
async: true,
data: JSON.stringify(parameters),
success: function (data) {
//...do whatever with the data
},
failure: function (msg) {
//... show a message of error
}
});
}
});
</script>

Using a javascript object in 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

Categories

Resources