I am trying to send JSON to an Action method:
[HttpPost]
public virtual ActionResult KoUpdateAccount(CostCentreDTOX cc)
{
if (cc.NameCC == null)
{
return Json(new { message = "Im null" });
}
else
{
string s = cc.NameCC;
return Json(new { message = s });
}
}
Where CostCentreDTOX is defined as:
[Serializable]
public class CostCentreDTOX
{
public int CostCentreId { get; set; }
public int IdTransactionType { get; set; }
public string NameCC { get; set; }
}
The Json is created by doing (I am using Knockoutjs):
var json = ko.toJSON(this.costCentres()[0]);
This produces the following string (which is what I want):
"{"CostCentreId":5,"IdTransactionType":2,"NameCC":"Impuestos"}"
The method that sends everything to the server is:
this.save = function() {
var json = ko.toJSON(this.costCentres()[0]);
api.postCud({
url: "/admin/Accounts/KoUpdateAccount/",
dataType: 'JSON',
data: json,
type: "post",
contentType: "application/json; charset=utf-8",
success: function(result) { alert(result.message) }
});
}
Where this.costCentre()[0] is an object defined as follows:
function costCentre(CostCentreId, IdTransactionType, NameCC) {
this.CostCentreId = ko.observable(CostCentreId);
this.IdTransactionType = ko.observable(IdTransactionType);
this.NameCC = ko.observable(NameCC);
}
However, the Action parameter cc just gets instantiated to its default values, as if the JsonValueProvider wasn't registered. But I am using ASP.NET MVC 3, so it should be there, right? Just there.
EDIT:
I have tried adding the following to the Global.asax file:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
}
But still, cc gets instantiated with default values.
any suggestions??
Is the api.postCud is that doing something exotic that could problems when it executes the post? Have you tried with $.ajax() instead just to see it that works?
As #Major Byte suspected, there was an issue with they way the ajax call was being made. This is done via a method, api.postCud, defined on an api.
The method is just a wrapper around $.ajax (see Eric Sowell's MvcConf2 video: Evolving Practices in Using jQuery and Ajax in ASP.NET MVC Applications). The problem being that it merges the options for the $.ajax call using $.extend() and I had included no provision for the dataType option.
So MVC was unaware that JSON was being posted, and therefore the model binding wasn't working.
This is what happens when I get 2 hours sleep...
Related
The following is an example of the basic structure/goal:
javascript ajax structure:
helper = someBaseClass.extend({
init: function () {
},
makeRequest: function (options) {
return createAjaxObservable(
{
url: options.url,
data: JSON.stringify(options.data), //stringify is present
type: options.type,
contentType: 'application/json; charset=utf-8',
dataType: "json",
cache: false
});
}
});
server javascript request:
this.helper.makeRequest({ url: "/Session/RequestSomeInfo", type: "POST", data: { sessionId: options.sessionId, requestSomeInfo: { isActive: true } });
Request some arbitary info on sessionId, for all arbitary entities that are active.
I am using post here for testing purposes.
controller method:
[HttpPost]
public JsonResult RequestSomeInfo(Session sessionId, RequestSomeInfo request)
{
//implement api connection
//request some arbitary info on sessionid, for all arbitary entities that are active.
return CreateJson(true, new { Data = requestSomeInfoResponse.Data });
}
The above is the ideal solution.
I am aware it may not be possible.
What would be the best alternative solution?
I have omitted [FromBody]. [FromBody] I understand only will pass one parameter. I can get the above general structure to work, using[FromBody], but it'll only pass one parameter.
I have also tried using a wrapper class - which contains Session and RequestSomeInfo, then passing this wrapper class. This also works.
However, the problem being that RequestSomeInfo could be requesting different things across an extensive web app. For example, RequestSomeInfo could be RequestCustomerNames, RequestActivities, RequestSocialConnections, etc.
--> the objects I want to pass can get complex.
I can use abstraction, or generics to accomplish this. Using generics on the wrapper class works, and is so far the best solution, however, this isn't the ideal solution. Ideally, I want to implement the above basic goal and structure as closely as possible.
Ajax cannot map multiple complex types at the same time, it can only pass multiple basic types at the same time. A better approach is to create a ViewModel to refer to these two complex types.
Since you did not give the full ajax implementation code, I use jQuery's ajax as an example. The Session here is customized by default.
Here is the all model.
public class Session
{
public int sessionId { get; set; }
}
public class RequestSomeInfo
{
public bool isActive { get; set; }
}
public class ViewModel
{
public Session Session { get; set; }
public RequestSomeInfo RequestSomeInfo { get; set; }
}
The Ajax code is as follows (it put in Index.cshtml).
$(function () {
$.ajax({
url: '/Session/RequestSomeInfo',
type: 'post',
data: {
session: {
sessionId: '123'
},
requestSomeInfo: { isActive: true }
},
success: function (data) {
console.log(data)
},
error: function () {
}
})
})
The controller is changed like this.
[HttpPost]
public JsonResult RequestSomeInfo(ViewModel viewModel)
{
return Json(viewModel);
}
And you can get this result.
I am trying to pass a single boolean value via ajax to a server API.
The API action is hitted but the parameter (shuffled) is false, though I am setting it to true via Ajax.
The api controller action is this:
[HttpPost("PostShuffled")]
public IActionResult PostShuffled([FromBody]bool shuffled)
{
userSession.Shuffled = shuffled;
return Ok();
}
My Ajax call is this:
function ChangeViewMode(el) {
if (el.id == "ViewShuffled") {
$.ajax({
url: "/api/Data/PostShuffled",
contentType: "application/json",
method: "POST",
data: JSON.stringify({ shuffled: true }),
success: function () { alert("ok"); }
});
}
}
My question is what am I doing wrong?
Ok I have solved the problem this way:
Defined a new class:
public class AjaxShuffled
{
public bool shuffled { get; set; }
}
Then in my controller changed:
[HttpPost("PostShuffled")]
public IActionResult PostShuffled([FromBody]AjaxShuffled s)
{
userSession.Shuffled = s.shuffled;
return Ok();
}
And now the value is passed correctly. I had to encapsulate the boolean into a class to make it work.
The problem is that shuffled is wrapped in an object instead of sent by itself. If you only want to send a boolean value, just send true or false itself: data: true or data: JSON.stringify(true) depending on how you've configured your web service to handle input formats for boolean. On the server side you should only need the [FromBody] descriptor on the API method parameter.
Failed to post complex object with list to asp.net core api using jquery ajax
Here is the Models
public class Bus
{
public int BusId { get; set; }
public string RegistrationNo { get; set; }
public IEnumerable<BusSeat> BusSeats { get; set; }
}
public class BusSeat : CoreModel
{
public int DecNumber { get; set; }
public int SeatId { get; set; }
}
Here is the Controller
[HttpPost]
public IActionResult Save([FromForm] Bus bus)
{
return Ok(bus);
}
Here is the javascript
var d = {
BusId: 1,
RegistrationNo: 'REG123',
BusSeats: [
{
DecNumber: 1,
SeatId:2,
},
{
DecNumber: 1,
SeatId: 4,
}
]
}
$.ajax({
type: 'post',
url: 'http://localhost:46060/api/bus/save',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify({ bus: d }),
success: function (data) {
},
error: function (data) {
}
});
Request is successful, but i couldn't get any data. Anything i am missing?
You don't need stringify, contentType on ajax call, and don't need [FromForm] on the mvc action.
Just pass the complex object directly on the data parameter.
$.ajax({
type: 'post',
url: 'http://localhost:46060/api/bus/save',
dataType: 'json',
data: d,
success: function (response) {
},
error: function (response) {
}
});
As long as the complex json object matches the view models you define, the binding should 'magically' work.
[HttpPost]
public IActionResult Save(Bus bus)
{
return Ok(bus);
}
This is off topic but you should think about how you construct your uris since you're building web api. You don't want to still use good old RPC style on your uri.
Think about the controller name as resource collection, and use HttpMethod as verb.
So I would create BusesController instead of BusController (Or use [RoutePrefix("api/buses")]), because I think about the resource as a collection - buses.
[Route("api/[controller]")]
public class BusesController : Controller
{
// GET api/buses
[HttpGet]
public IActionResult()
{
// Return all buses
return OK(...);
}
// GET api/buses/1
[HttpGet]
public IActionResult(int id)
{
// Return individual bus
return OK(...);
}
// POST api/buses
[HttpPost]
public IActionResult Post(CreateBusViewModel model)
{
// Create a new bus and return newly created uri of the bus
return Created(...);
}
}
You can read more about Richardson Maturity Model here!
Change the From part in the action to [FromBody] and in the ajax call for data just say
data: JSON.stringify(d)
Rather than
data: JSON.stringify({ bus: d })
I am using revealing module pattern and knockout to bind a form. When data is entered in that form(registration), it needs to be posted back to MVC4 web method.
Here is the Jquery code
/*
Requires JQuery
Requires Knockout
*/
op.TestCall = function () {
// Private Area
var _tmpl = { load: "Loading", form: "RegisterForm"};
var
title = ko.observable(null)
template = ko.observable(_tmpl.load),
msg = ko.observable(),
postData = ko.observable(),
PostRegistration = function () {
console.log("Ajax Call Start");
var test = GetPostData();
$.ajax({
type: "POST",
url: obj.postURL, //Your URL here api/registration
data: GetPostData(),
dataType: "json",
traditional: true,
contentType: 'application/json; charset=utf-8'
}).done(Success).fail(Failure);
console.log("Ajax Call End");
},
GetPostData = function () {
var postData = JSON.stringify({
dummyText1: dummyText1(),
dummyText2: dummyText2(),
});
return postData;
}
return {
// Public Area
title: title,
template: template,
dummyText1: dummyText1,
dummyText2: dummyText2
};
}();
The controller code is simple as per now
// POST api/registration
public void Post(string data)
{
///TODO
}
When i am trying to, capture the data (using simple console.log) and validate it in jslint.com, it's a valid Json.
I tried hardcoding the data as
data: "{data: '{\'name\':\'niall\'}'}",
But still i get as null, in my web method.
Added the tag [System.Web.Script.Services.ScriptMethod(UseHttpGet = false, ResponseFormat = System.Web.Script.Services.ResponseFormat.Json)] to my Post method in controlled, but still no fruitful result
Even tried JSON.Stringify data: JSON.stringify(data) but still i get null in my web-method.
I am not able to figure out the solution.
Similar issue was found # this link
http://forums.asp.net/t/1555940.aspx/1
even Passing parameter to WebMethod with jQuery Ajax
but didn't help me :(
MVC and WebApi uses the concept of Model Binding.
So the easiest solution is that you need to create a Model class which matches the structure of the sent Json data to accept the data on the server:
public void Post(MyModel model)
{
///TODO
}
public class MyModel
{
public string DummyText1 { get; set; }
public string DummyText1 { get; set; }
}
Note: The json and C# property names should match.
Only escaped double-quote characters are allowed, not single-quotes, so you just have to replace single quotes with double quotes:
data: "{data: '{\"name\":\"niall\"}'}"
Or if you want to use the stringify function you can use it this way:
data: "{data: '" + JSON.stringify(data) + "'}"
I know this has been asked before in a similar form, but I have hit a bit of problem here....
I have this classic problem of trying to pass a json complex type to MVC2.
The problem (refer to the code below): I can pass the value "subincidentID" to the controller but the values "CodeType", "MOCode" and "SubCode" are all NULL.
I HAVE installed the MVC2 future and registered "Microsoft.Web.MVC" in global.asax.cs and declare the JsonValueProviderFactory.
The JQuery bit:
$('#btnDone').click(function() {
var entity = {};
var dbCode = new Array();
dbCode[0] = { CodeType: "1", MoCode: "13", SubCode: "12" };
entity = { subincidentID: "1", codeData: dbCode };
$.ajax({
type: 'POST',
data: entity,
dataType: 'json',
async: false,
url: "/controller/SaveMOData",
success: function(result) {
alert('success!');
}
}); //end of post
}); //end of btnDone click function
Controller in MVC:
[HttpPost]
public JsonResult SaveMOData(MOSubMitModel mo)
{
if (ModelState.IsValid)
{
}
return Json(new { success = "true" });
}
Model class in MVC (2):
public class MOSubMitModel
{
public int subIncidentID { get; set; }
public List<dbCode> codeData { get; set; }
}
public class dbCode
{
public string CodeType { get; set; }
public string subCode { get; set; }
public string MoCode { get; set; }
}
Have I missed something here?
Do I have to declare any namespace on the controller page?
I am sure it is a small problem but I have been scratching my head the whole day about it....:-(..
Thanks in advance.
W. Lam
I've heard of issues using the following syntax
$.ajax({
type: "POST",
data: {prop:"Value"},
....
}
Instead you need to stringify the object
$.ajax({
type: "POST",
data: JSON.stringify({prop:"Value"}),
....
}
After some more trial-and-error and readings I have finally figured it out myself (Refer to the previous posting for details of the other components):
$('#btnDone').click(function() {
:
:
$.ajax({
type: 'POST',
data: JSON.stringify(entity),
contentType: 'application/json',
async: false,
url: "/controller/SaveMOData",
success: function(result) {
alert('success!');
}
}); //end of post
}); //end of btnDone click function
The problem was me NOT to include "contentType" (I had tried to inclide json stringify before but it ALL returns NULL if I do not include contentType)...so...to summarise the requirements under MVC2:
Download MVC Future .....Unzip the MVC future zip file and copy Microsoft.web.mvc to your project, and reference it In your project's global.asax.cs file, include the "Microsoft.web.mvc" namespace, and then include the following line at the end of the function "Application_start"
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
Make the necessary changes in your jQuery as indicated above. It should be working (well it works for me!!)..Hope it helps anyone with the same problem.