Jquery post to mvc 4 controller not passing data - asp.net-mvc

I'm trying to pass data from JQuery to an MVC 4 controller. The controller gets invoked, but no data is passed. In the past I always just used form serialization, but that's not appropriate here.
My Controller:
[HttpPost]
public ActionResult Write(VideoSessionEnvelope envelope)
{
if (ModelState.IsValid)
{
envelope = Log.Write(envelope);
}
var result = Json(envelope);
return result;
}
We use an envelope class as a container for all view models
public class VideoSessionEnvelope : BaseEnvelope
{
public VideoSessionEnvelope()
{
SessionStart = new VideoSessionStartViewModel();
}
public Guid? LogEntryID { get; set; }
public VideoSessionStartViewModel SessionStart { get; set; }
}
}
The view model
public class VideoSessionStartViewModel: IViewModel
{
public string SessionId { get; set; }
public int UserId { get; set; }
public string Message { get; set; }
}
And finally the javascript
var Logging = Logging || {};
Logging.VideoSession = function () {
var Start = function (sessionId, userId, message) {
var envelope = {
SessionStart: {
"SessionId": sessionId,
"UserId": userId,
"Message": message
}
}
var data = JSON.stringify(envelope);
$.ajax({
type: "POST",
url: "/Logging/Write",
data: data,
datatype: "application/json",
success: function (result) {
return result;
},
error: function (request, status, error) {
return error;
}
});
};
return {
Start: Start
};
}();
According to Firebug the data is passed as
JSON
SessionStart Object { SessionId="sessionIdVal", UserId=123, Message="messageValue"}
Message "messageValue"
SessionId "sessionIdVal"
UserId 123
The controller gets called, but the properties in the view model are always null. I've tried several variations on the theme, nothing seems to work.

Try wrapping your data in a literal with the name as envelope so it will be picked up by the Model Binder:
data: { envelope: data },
UPDATE
Remove the call to JSON.stringify(), it is not strictly necessary to serialize the object literal.

Related

How to post json object with multiple values to the Controller from Ajax

I have this Ajax post working for a single value but I need it to work with multiple values. What am I missing?
I have already tried to make the public class 'Value' a List AND Guid[]. I have tried to adjust the method parameter to List AND Value[]. Not sure what else to try.
Class:
public class Value
{
public Guid TimeId { get; set; }
}
Method:
public IActionResult ApproveAllTimesheets([FromBody]Value information)
View JS:
function SubAll() {
var selectedValues = $('#timesheet').DataTable().column(0).checkboxes.selected().toArray();
var instructions = {};
for (var TimeId in selectedValues) {
instructions[TimeId] = { TimeId: selectedValues[TimeId] };
}
var inst = JSON.stringify(instructions);
$.ajax({
url: "/Admin/ApproveAllTimesheets",
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: inst,
success: function (result) {
alert(result);
},
error: function (xhr, textStatus) {
if (xhr.status == 401) { alert("Session Expired!"); window.location = "/Account"; }
else {
alert('Content load failed!', "info");
}
}
});
};
If I send through this object it works but I need to send through multiple values like my ajax post will do.
var instructions = { TimeId: "13246578-1234-7894-4562-456789123456" };
UPDATE #1
I found a structure that works for me by extending the class, now I just need to figure out how to create the correct object and array combination.
New Classes:
public class ValueContainer
{
public List<Value> MasterIds { get; set; }
}
public class Value
{
public Guid TimeId { get; set; }
}
Method:
public IActionResult ApproveAllTimesheets([FromBody]ValueContainer information)
Structure I need now (this works hard coded):
var jsonObject = {
"MasterIds": [{ TimeId: "13246578-1234-7894-4562-456789123450" }, { TimeId: "13246578-1234-7894-4562-456789123451" }, { TimeId: "13246578-1234-7894-4562-456789123452" }]
};
I'm still new to this stuff but what I see is that jsonObject is an object with a Key 'MasterIds' and the corresponding values are an array of objects with the key 'TimeId'...is this a correct evaluation?...and how to create it in code please?
You neec to create an array of objects and then set it in the container object :
var instructions = []; // an array
for (var i = 0; i < selectedValues.length; i++) {
instructions.push({ TimeId: selectedValues[i] };
}
var Value = {TimeId: instructions}; // creating object with property TimeId as array of guid
var inst = JSON.stringify(Value);
.......
....... your ajax code
and your class property should also be of type array:
public Guid[] TimeId { get; set; }

How to return callback json from VC Controller?

I am using 3rd party Kendo UI in client side. it expects data from server in below format.
callback([{"TaskID":4,"OwnerID":2,"Title":"Bowling}])
I am having below code in server side
public JsonResult GetAllAppointments()
{
IEnumerable<AppointmentModel> appointmentCollection = app_repository.GetAll();
if (appointmentCollection == null)
{
return Json(appointmentCollection, JsonRequestBehavior.AllowGet);
}
return Json(appointmentCollection, JsonRequestBehavior.AllowGet);
}
But this returns just json, how to add "callback" to it?
Ideally you should get an interceptor at client side which should let you modify your response format..but since you have not provided any further details I won't be able to comment on that.
You can change your return type fron JsonResult to string and manually serialize your response.You can use Json.NET to serialize your response.
Here is a NuGet LINK for the same.
public class AppointmentModel
{
public string TaskID { get; set; }
public string OwnerID { get; set; }
public string Title { get; set; }
}
public string GetAllAppointments()
{
string responseFormat = #"callback({0})";
IEnumerable<AppointmentModel> appointmentCollection = getDummyAppoitments();
if (appointmentCollection != null)
{
string json_string = Newtonsoft.Json.JsonConvert.SerializeObject(appointmentCollection);
return string.Format(responseFormat, json_string);;
}
//no items were present so sending empty response;
return string.Format(responseFormat, "[]");;
}
private IEnumerable<AppointmentModel> getDummyAppoitments()
{
return new List<AppointmentModel>() {
new AppointmentModel()
{
TaskID = "4",
OwnerID = "2",
Title = "Bowling"
}
};
}
Check out response.
Cheers!!

Json to List<object> not binding

I have a problem with object send in json format, that is not binded in Action Controller
Here the json parts:
function filterTxAjustement(arrTx) {
return {
dateDebut: $("#TxAjustementDateDebut").val(),
dateFin: $("#TxAjustementDateFin").val(),
ufCode: $("#TxAjustementUf").val(),
tx: JSON.stringify(arrTx)
};
}
function SaveTx() {
var arrTx = [];
$.each(Day, function (i, v) {
var $this = $('#' + v + 'Tx');
var tx = new Object();
tx.Day = v;
tx.Nb = parseInt($this.val());
tx.UfCode = parseInt($('#TxAjustementUf').val());
tx.Total = 0;
arrTx.push(tx);
});
$.ajax({
url: EasilyRelativeUrl("Lit/SetTxAjustementByDateAndUf"),
data: filterTxAjustement(arrTx),
type: 'POST',
dataType: 'json'
}).done(function (data) {
$('#TxAjustementGrid').data("kendoGrid").dataSource.read();
});
}
My array is well populated:
dateDebut:16/12/2013
dateFin:22/12/2013
ufCode:21124
tx:[{"Day":"Sunday","Nb":1,"UfCode":21124,"Total":0},{"Day":"Monday","Nb":2,"UfCode":21124,"Total":0},{"Day":"Tuesday","Nb":3,"UfCode":21124,"Total":0},{"Day":"Wednesday","Nb":0,"UfCode":21124,"Total":0},{"Day":"Thursday","Nb":0,"UfCode":21124,"Total":0},{"Day":"Friday","Nb":0,"UfCode":21124,"Total":0},{"Day":"Saturday","Nb":0,"UfCode":21124,"Total":0}]
But when it hit Action Controller, tx is null
public ActionResult SetTxAjustementByDateAndUf(DateTime dateDebut, DateTime dateFin, string ufCode, List<TauxAjustement> tx)
(Here the TauxAjustement object)
public class TauxAjustement
{
public string Day { get; set; }
public int Nb { get; set; }
public int Total { get; set; }
public int UfCode { get; set; }
}
I have tried with TauxAjustement[], but same issue. I have added Total = 0 and parseInt to have exact definition of C# object, but same...
What have I missed ? I do make a CustomBinderModel for this ?
Thanks for your help.
You need to define the tx argument as an array rather than a List:
public ActionResult SetTxAjustementByDateAndUf(DateTime dateDebut,
DateTime dateFin,
string ufCode,
TauxAjustement[] tx)
{}

Breeze Controller not returning proper response

I have a simple model, it is Entity Framework 5 Code First, ActiveEntity is an abstract class with an int Id property and a bool IsActive field.
public class License:ActiveEntity
{
public string LicenseName { get; set; }
public LicenseType LicenseType { get; set; }
public State State { get; set; }
public DateTime DateIssued { get; set; }
public int ValidFor { get; set; }
}
public class LicenseType:ActiveEntity
{
[StringLength(100),Required]
public string Description { get; set; }
}
public class State:ActiveEntity
{
[StringLength(2)]
[Required]
public string Name { get; set; }
[Display(Name = "Long Name")]
[Required, StringLength(25)]
public string LongName { get; set; }
}
Breeze makes a call to GetLicenses on the LicenseController:
[BreezeController]
public class LicenseController : ApiController
{
private readonly EFContextProvider<LicensingContext> db = new EFContextProvider<LicensingContext>();
[HttpGet]
public string Metadata()
{
return db.Metadata();
}
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return db.SaveChanges(saveBundle);
}
[HttpGet]
public IQueryable<License> GetLicenses()
{
//for debugging purposes
var retVal = db.Context.Licenses
.Include(l => l.State)
.Include(l=>l.LicenseType);
return retVal;
}
}
The db context returns the appropriate data but it does not appear in the response.
I don't have enough reputation points to post an image but the license type and state are in the context's response.
However the controller's response does not contain the licensetype object for the first three objects.
[{"$id":"1","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Low Voltage","State":{"$id":"2","$type":"Volt.Telecom.Licensing.Models.State, Volt.Telecom.Licensing.Models","Name":"FL","LongName":"Florida","IsActive":false,"Id":23},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":1},{"$id":"3","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Contractors","State":{"$ref":"2"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":2},{"$id":"4","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"General Contractors","State":{"$ref":"2"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":3},{"$id":"5","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Low Voltage","LicenseType":{"$id":"6","$type":"Volt.Telecom.Licensing.Models.LicenseType, Volt.Telecom.Licensing.Models","Description":"Low Voltage","IsActive":false,"Id":1},"State":{"$id":"7","$type":"Volt.Telecom.Licensing.Models.State, Volt.Telecom.Licensing.Models","Name":"CA","LongName":"California","IsActive":false,"Id":35},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":4},{"$id":"8","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Contractors","LicenseType":{"$id":"9","$type":"Volt.Telecom.Licensing.Models.LicenseType, Volt.Telecom.Licensing.Models","Description":"Contractors","IsActive":false,"Id":2},"State":{"$ref":"7"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":5},{"$id":"10","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"General Contractors","LicenseType":{"$id":"11","$type":"Volt.Telecom.Licensing.Models.LicenseType, Volt.Telecom.Licensing.Models","Description":"General Contractors","IsActive":false,"Id":3},"State":{"$ref":"7"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":6}]
Here is the home.js file on the client.
define(['services/logger'], function (logger) {
var system = require('durandal/system');
var serviceName = 'api/License';
// manager is the service gateway and cache holder
var manager = new breeze.EntityManager(serviceName);
var vm = {
activate: getLicenses,
title: 'Licenses',
licenses: ko.observableArray(),
includeExpired: ko.observable(false),
save: saveChanges,
show: ko.observable(false)
};
//vm.includeExpired.subscribe(getLicenses);
function getLicenses() {
log("querying Licenses", null, true);
var query = breeze.EntityQuery.from("GetLicenses");
//if (!vm.includeExpired()) {
// query = query.where("DateIssued.AddDays(ValidFor*-1)" > new Date(Date.now()));
//}
return manager
.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
// reload vm.todos with the results
function querySucceeded(data) {
log("queried Licenses", null, true);
vm.licenses(data.results);
vm.show(true); // show the view
}
}
function queryFailed(error) {
log("Query failed: " + error.message, null, true);
}
function saveChanges() {
return manager.saveChanges()
.then(function () { log("changes saved", null, true); })
.fail(saveFailed);
}
function saveFailed(error) {
log("Save failed: " + error.message, null, true);
}
function log(msg, data, showToast) {
logger.log(msg, data, system.getModuleId(vm), showToast);
}
return vm;
//#endregion
});
Any thoughts as to why this would occur and only for the first three items, any help would be appreciated. I like breeze as a potential for some spa's we need to write but this has caused me some concern.
Update 1
If I change the order of the LicenseType_id in the database it works, the initial order was 123123
if it is changed to 312123 or 321123 all six are correct in the response
[{"$id":"1","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Low Voltage","LicenseType":{"$id":"2","$type":"Volt.Telecom.Licensing.Models.LicenseType, Volt.Telecom.Licensing.Models","Description":"General Contractors","IsActive":false,"Id":3},"State":{"$id":"3","$type":"Volt.Telecom.Licensing.Models.State, Volt.Telecom.Licensing.Models","Name":"FL","LongName":"Florida","IsActive":false,"Id":23},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":1},{"$id":"4","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Contractors","LicenseType":{"$id":"5","$type":"Volt.Telecom.Licensing.Models.LicenseType, Volt.Telecom.Licensing.Models","Description":"Low Voltage","IsActive":false,"Id":1},"State":{"$ref":"3"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":2},{"$id":"6","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"General Contractors","LicenseType":{"$id":"7","$type":"Volt.Telecom.Licensing.Models.LicenseType, Volt.Telecom.Licensing.Models","Description":"Contractors","IsActive":false,"Id":2},"State":{"$ref":"3"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":3},{"$id":"8","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Low Voltage","LicenseType":{"$ref":"5"},"State":{"$id":"9","$type":"Volt.Telecom.Licensing.Models.State, Volt.Telecom.Licensing.Models","Name":"CA","LongName":"California","IsActive":false,"Id":35},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":4},{"$id":"10","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Contractors","LicenseType":{"$ref":"7"},"State":{"$ref":"9"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":5},{"$id":"11","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"General Contractors","LicenseType":{"$ref":"2"},"State":{"$ref":"9"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":6}]
Edit: As of v 1.3.1 Breeze now DOES support inheritance.
The problem may be that Breeze does not yet support inheritance. There is a UserVoice suggestion here. Please vote on it. We take these suggestions very seriously.
To confirm that this is your issue, can you flatten the structure so that you do not need inheritance and see if the issue goes away.
I think that if something disappears between server to client its because Breeze retain null data column which can disorganize data structure and make knockout binding dysfunctional.
In opting to minimize Breeze performance you can place the attribute in the down level according to your need.
1 - BreezeWebApiConfig.cs level
2 - Controller level
3 - or HttGet level
This attribute works for me:
var jsonx = Breeze.WebApi.BreezeConfig.Instance;
jsonx.GetJsonSerializerSettings().NullValueHandling = Newtonsoft.Json.NullValueHandling.Include;

Return multiple objects using Json.Net

With the built-in json converter I return multiple objects in my action like this:
return Json(new { success = true, data = units });
When I use the JSON.NET library how can I do the same?
This does obviously not compile:
return new { success = true, data = JsonConvert.SerializeObject(units) };
I do not want to create an extra viewmodel for this containing both properties.
Do I have a wrong understanding of the default Json javascript serializer maybe ?
If you want to use Newtonsoft.Json to serialise your objects, you can create a new ActionResult class and pass the data in the result.
For example:
public class NewtonsoftJsonResult : ContentResult
{
private readonly object _data;
public NewtonsoftJsonResult(object data)
{
_data = data;
}
public override void ExecuteResult(ControllerContext context)
{
Content = JsonConvert.SerializeObject(_data);
ContentType = "application/json";
base.ExecuteResult(context);
}
}
Just return your custom ActionResult with the anonymous object as data:
public ActionResult Index()
{
return new NewtonsoftJsonResult(new { success = true, data = units});
}
In your second example, JsonConvert.SerializeObject(units) will result in a string returned to JavaScript. JavaScript won't see data as containing some "real" data but rather a simple string, with curly parentheses inside.
Use your first sentence as usual. MVC's Json method will serialize the objects within.
For example:
class Units
{
public int Width { get; set; }
public int Height { get; set; }
}
...
Units u = new Units { Width = 34, Height = 20 };
return Json(new { success = true, data = units });
will result in a Json that looks similar to this:
{ "success" : "true", "data" : { "Height" : "20", "Width" : "34" } } }

Resources