So, some time ago, I needed to make ajax requests to access the code behind. I did that (here).
But now I'm working on asp.NET Core 2.0 and it works differently. Well, now I can make a request but, for some reason The variables are null (only on the code behind, on the client side they have content. Probably isn't a big deal, but I can't grasp why.
So, here's my ajax function:
function Ajax(expression1, expression2, url, json, error) {
console.log(expression1+" - "+ expression2);
var request = { email: expression1, password: expression2 }
$.ajax({
url: url,
method: 'post',
contentType: 'application/json',
data: JSON.stringify(request),
dataType: 'json',
success: function (resp) {
console.log(request);
if (expression1 === null || expression2===null)
window.location.href = resp[json];
else
document.getElementById(error).innerHTML = resp[json];
},
error: function (error) {
}
})
}
And the c# code:
public string ExternalLogin(string email, string name)
{
//TODO: Facebook login
// Redirect link example. Could be another one.
return "{\"facebook\":\"Home/About\"}";
}
The ajax function makes the request and it triggers the c# function, and returns what I ask it to. The only problem is the null variables. Why is this happening?
EDIT: The User class as requested:
public class User
{
[JsonProperty(PropertyName ="email")]
public string Email { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "password")]
public string Password { get; set; }
}
The parameter binding fails because you are making a post request here.
You have to add the [FromBody] attribute to your parameters.
You can get more info about paramter binding here:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
EDIT:
You also passing a object as paramter so you either have to change you route paramter to an object containing email and password property, or you change your Content-Type to 'application/x-www-form-urlencoded' and pass a query string like 'email=....&password=....'
Related
Before I begin, I'd like to say - I realize that this question is very similar to many others that have been posted and answered on this site. I have read through and tried as many solutions as I could find that was related to my issue, and none have worked thus far.
I'm attempting to pass data from my web page to a controller method. The web page is very simple and only needs to capture information input by the user and send it off. I'm using Telerik's Kendo Grid to bind to and organize my data. No matter what I try, though, my AJAX post request never passes parameters forward correctly. When using my browser's debugger, I can see that the parameters being passed into the AJAX request are valid, but by the time they hit my breakpoint in the controller method, they are all either null or default.
Function Containing AJAX Request
function saveShiftDataToServer() {
var grid = $("#myGrid").data("kendoGrid");
var dataSource = grid.dataSource;
var allData = dataSource.data();
var comments = '#Model.Comments';
var loadInfoCorrect = '#Model.LoadInfoCorrect';
$.ajax({
type: "POST",
url: '/Home/SaveData',
data: JSON.stringify({ accessorials: allData, comments: comments, loadInfoCorrect: loadInfoCorrect }),
contentType: "application/json; charset=utf-8",
datatype: "json"
})
}
Controller Method
[AcceptVerbs("Post")]
public ActionResult SaveData(Accessorial[] accessorials, string comments, bool loadInfoCorrect)
{
// Code removed for brevity
}
My Kendo Grid is typed as Accessorial (the first controller method parameter type), so my assumption is that retrieving a collection of all present rows should return an array of that model. Even so, "comments" is a string, but is only ever passed to the controller method as null.
I'm new to ASP.NET Core and Kendo, so I'm sure there is something obvious that I'm missing. Any help would be appreciated!
I appreciate all of the responses! I was able to finally see valid data in my controller by changing the AJAX data type to "text" and simply passing the JSON directly for deserialization server-side. For some reason this is the only way that I've been able to make this work thus far.
AJAX POST Call
function saveShiftDataToServer() {
var grid = $("#accessorialGrid").data("kendoGrid");
var dataSource = grid.dataSource;
var allData = dataSource.data();
var shiftOverview = {
ShiftId: 0,
UserName: "test",
ShiftDate: null,
LoadList: null,
AccessorialList: allData,
LoadInfoCorrect: true,
Comments: ""
};
var jsonData = JSON.stringify(shiftOverview);
$.ajax({
type: "POST",
url: '/Home/SaveData',
data: { json: jsonData },
datatype: "text",
success: function (response) {
alert("111");
}
})
}
Controller Method
[AcceptVerbs("Post")]
public ActionResult SaveData(string json)
{
JsonConvert.DeserializeObject<ShiftOverview>(json); // This produces an object with valid data!
}
You could pass all your data in a ViewModel and get access to it using [FromBody] on action
public class ViewModel
{
public List<Accessorial> Accessorials{ get; set; }
public string Comments { get; set; }
public bool LoadInfoCorrect { get; set; }
}
Ajax:
var model = {};//pass all you data to an object
model.Accessorials = allData ;
model.comments = comments ;
model.loadInfoCorrect = loadInfoCorrect;
var items = JSON.stringify(model);
$.ajax({
url: '/GetAllCustDetails/SaveData',
type: "POST",
data: items,
contentType: 'application/json; charset=utf-8',
//dataType: "json",
success: function (response) {
alert("111");
}
});
Controller:
[HttpPost]
public ActionResult SaveData([FromBody]ViewModel model)
You are passing JSON object which corresponds to C# one like this:
public class Model {
public Accessorial[] Accessorials { get; set; }
public string Comments { get; set; }
public bool loadInfoCorrect { get; set; }
}
Try to declare such class above and adjust your action method this way:
public ActionResult SaveData(Model model)
{
// Code removed for brevity
}
If won't help - make model parameter object and check in debug mode what you are getting from AJAX call.
You juste have to use the [FromBody] attribute in your action method, like this :
[HttpPost]
public ActionResult SaveData([FromBody]Model model)
{
// Code removed for brevity
}
I am using JSGrid to allow me to modify data. I am trying to setup the updateItem as follows:
updateItem: function (item) {
return $.ajax({
type: "PUT",
url: "/api/data/" + item.logID,
data: item,
contentType: "application/json;charset=utf-8",
dataType: "json"
});
}
I have a model as follows:
public class LogEntry
{
public string firstName { get; set; }
public string lastName { get; set; }
public string comment { get; set; }
public bool modified { get; set; }
public DateTime inTime { get; set; }
public DateTime outTime { get; set; }
public double totalHrs { get; set; }
public int logID { get; set; }
}
Here is my ApiController Class that contains the Put method:
public class DataController : ApiController
{
public void Put(int id, [FromBody]LogEntry item)
{
if(item != null)
{
//DO STUFF
}
}
}
However no matter what I do the item is always Null. I have tried the following:
Change to [FromBody]JObject item
Change to [FromBody]String item
Change the data: field to Json.Stringify
Change to [FromBody]String to just String
Add and remove context type of application/json;charset=utf-8 to the updateItem ajax call.
I have used Fiddler to see the data sent back. It shows the correct JSON being sent but the Put method doesn't seem to be getting that data.
Any ideas on what might be causing this behavior would be great. I have been researching around but nothing has worked yet.
Resolution Notes
It turned out that both answers from Caz1224 and CodeFuller aided in fixing this. CodeFuller's way of finding the error message lead me to the JSON coming back to the server. It was messed up even though Fiddler said it was correct. I changed my Ajax call to stringify the item. Which then matched my Model exactly.
return $.ajax({
type: "PUT",
url: "/api/data/" + item.logID,
data: JSON.stringify(item),
contentType: "application/json; charset=utf-8",
dataType: "json"
FromBody attribute is not strictly required here because non-simple types are built by the default from the request body.
I don't see any problems with your code so far, it should work for valid request. Seems like the problem is with the request sent and it causes model binding error. To proceed with the analysis check the following:
Check the value of ActionContext.ModelState.IsValid in Put() method. Is it true or false?
If it's false, check collection ActionContext.ModelState.Values in debugger. It should contain model binding errors that will hint you were the problem actually happens.
I had this issue and its painful!!
This is what ended up working for me.
The first part is my javascript (I guess that is how you are making your JSON)
"List" is my array that PERFECTLY matches (Even to the case, it matters) to my C# model.
Javascript Build List
var List = [];
$.each(_questions, function () {
var limitID = this.id.substr(-1);
var Quest = $('#Quest_' + ID).val();
var objectpush = {
LimitID: limitID,
Quest: Quest,
ID: ID
}
List.push(objectpush);
Then in the AJAX call further on I specify data like so:
data: JSON.stringify(List),
And finally this is on my C# API
public JsonResult QueryLimits(int UserID, [FromBody] List<List> List)
Hope this helps get you on the track. Don't just copy the code as I changed the name to List throughout my code and that will cause issues!
Caz
I am designing a simple Web API service that takes the inputs on an html form, turns those inputs into json, and then sends that to a Web API. I am working with ASP.NET Web API in Visual Studio 2017. Here is some of my code to help me explain better:
This is my controller method that I am calling:
[HttpPost]
public AssessModel PostAssessment ([FromBody] AssessModel assess)
{
//Do something
return assess;
}
This is the model (simplified) that I'm using:
public class AssessModel
{
public Guid capitalassetassessmentid { get; set; }
public string ownerid { get; set; }
/*... Many more properties of int, bool, ect here ...*/
public string name { get; set; }
public string building { get; set; }
}
And finally this is the ajax call that I am using in my scripts:
$("form#my-form").submit(function (e) {
//First line here takes all fields and puts them in an array
var formArray = $(this).serializeArray();
//Second line takes that array and puts it into json format.
var jsonObj = JSON.stringify(formArray);
//Send request
$.ajax({
type: "POST",
url: "api/assessment/PostAssessment",
data: jsonObj,
contentType: "application/json",
dataType: "json",
success: function (jsonObj) {
$("#results").html(jsonObj.d);
}
});
});
So I am calling this ajax request when I submit a form. This ajax request should send my json as a string to the controller method but instead when I press submit I get an Error 405 - Method not Allowed. I am unsure why I am not allowed to send a POST verb to a controller method with the tag HttpPost.
It's also worth mentioning that my form tag is like this:
<form id="my-form" class="form" method="POST">
Any thoughts? Do I need to clarify anything? Let me know.
Try
var data = {};
var formArray = $('form#my-form').serializeArray();
for(var i in array)
{
data[formArray[i].name] = formArray[i].value;
}
var jsonObj = JSON.stringify(data);
I am trying to map Json to Dictionary. Earlier I had Dictionary with key of type 'long' . But after realizing for mapping to happen key needs to be of type 'string or 'object'.
Now my type definition in c# is like this :
public class StyleItemCreateCommand
{
public long StyleId { get; set; }
public Dictionary<String, string> SelectedItemToColorMap { get; set; }
}
And json which I am generating is like this:
{"StyleId":"1710","SelectedItemToColorMap":{"1391":"583","21531":"7733"}}
But still somehow it is not being mapped. I am using asp.net mvc controllers as a service, which is being consumed by jquery client.
MVC method signature is as following:
[HttpPost]
public ActionResult Create(StyleItemCreateCommand command)
{
}
The dictionary object is always null. Any help is appreciated. Thanks.
Now after searching around web I found out that ASP.Net MVC is not gonna do it implicitly. Found this answer :
[https://stackoverflow.com/a/15220050/756722]
I think the reason why this is happening is that
"SelectedItemToColorMap":{"1391":"583","21531":"7733"}
is an object and your StyleItemCreateCommand
class defines a Dictionary. Change the class property to:
public object SelectedItemToColorMap { get; set; }
and you should be able to see the values. You can then redesign your class/es.
Alternatively amend the json by surrounding the { } with [ ] converts SelectedItemToColorMap to an array of key value items.
UPDATE
Just tried in asp.net mvc 4 with a simple view
<input type="button" value="click1" id="click1" />
#Scripts.Render("~/bundles/jquery")
<script>
$(function () {
//this is called by a Get action on the controller
$('#click1').click(function (e) {
var jsonObject = { "StyleId": "1710", "SelectedItemToColorMap": { "1391": "583", "21531": "7733" } };
$.ajax({
url: "#Url.Action("Create")",
type: "POST",
data: JSON.stringify(jsonObject),
contentType: "application/json; charset=utf-8",
dataType: "json",
error: function (response) {
//process error;
},
success: function (response) {
//process success;
}
});
});
});
</script>
The above appears in the body of the view. And the controller is
[HttpPost]
public ActionResult Create(StyleItemCreateCommand command)
{
if (command != null) {
string value1 = command.SelectedItemToColorMap["1391"];
string value2 = command.SelectedItemToColorMap["21531"];
Debug.Assert(value1 == "583" && value2 == "7733");
}
return View();
}
Which uses your StyleItemCreateCommand - and it all works. Ok the above uses JSON.stringify(jsonObject) so what format is your json object that is actually coming from the post request? It would be interesting to see the request body (eg using chrome developer tools under the network section).
.Net serialization (not being used here) will wrap requests in a .d object as a security measure against auto execution of code, could this be what is happening?
I followed this tutorial to create a Restful web-api service.
Everything seemed to work well, I can get all the bookings in JSON format by requesting them from the correct url.
My issue is with the http POST.
My Javascript is:
var url = 'http://localhost:9077/api/bookings';
....
var newEvent = [];
newEvent.EventDateTime = // (now);
newEvent.Name = "MyFirstBooking";
function btnSubmit_Click()
{
alert("Submit clicked: " + newEvent.Name + "\n" + newEvent.EventDateTime);
$.ajax({
type: "POST",
url: url,
data: JSON.stringify( { Bookings: newEvent }),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) { alert(data); }
});
}
The alert displays the correct date and also the correct name.
When I click Submit and check fiddler it looks like the JSON is correctly formatted:
{"Bookings":[{"Name":"MyFirstBooking","EventDateTime":"2014-04-14T13:45:00.000Z"}]}
My View is Bookings.cs :
public class Bookings
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime BookingDateTime { get; set; }
public DateTime EventDateTime { get; set; }
public int Duration { get; set; }
public int UserID { get; set; }
}
In my BookingsController I have:
public HttpResponseMessage PostBooking(Bookings item)
{
// Implementation
}
However when I put a breakpoint after PostBooking, item.EventDateTime is {01/01/0001 00:00:00} and Name is null.
It seems like the JSON is not being deserialised correctly...? I'm not sure where this happens as I can't find it mentioned anywhere...
Thanks.
ahhh dates in javascript. Aren't they fun? You are more than likely going to have to do a converstion either in javascript or take a look at this stack overflow question to implement a custom date handler in your api:
ASP.NET Web API Date format in JSON does not serialise successfully
EDIT: Ahh i also noticed that your JSON object is an array. You will need to change your signature to take an array:
public HttpResponseMessage PostBooking(IEnumerable<Bookings> items)
{
// Implementation
}
EDIT AGAIN:
on second thought, I dont think your event needs to be an array. I think you want to do this:
var newEvent ={};
this will intialize newEvent as an object instead of a an array. then you can leave your signature as is. You might need to change your param name like tomasofen mentioned in his answer as well.
EDIT AGAIN:
further thought: you dont need to root the object with {"Bookings": newEvent } just do this instead:
$.ajax({
type: "POST",
url: url,
data: JSON.stringify(newEvent),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) { alert(data); }
});
you are setting the contentType to json. This tells your web app that the content should be json, which in turn will be handled and converted by the server. By stringifying it, you are turning the content into a string and therefore changing the contentType.
Try using the same name for the variable in the server method than the name of the Json parameter:
For server side:
public HttpResponseMessage PostBooking(Bookings item)
{
// Implementation
}
For client side (just change "item" as name of the param):
{"item":[{"Name":"MyFirstBooking","EventDateTime":"2014-04-14T13:45:00.000Z"}]}
I had issues with this, and perhaps this is your case. Tell us if it works or not to try other things.
Check also that the object Bookings in the server has the members Name and EventDateTime writen in the same way.