I have a Web API service call that updates a user's preferences. Unfortunately when I call this POST method from a jQuery ajax call, the request parameter object's properties are always null (or default values), rather than what is passed in. If I call the same exact method using a REST client (I use Postman), it works beautifully. I cannot figure out what I'm doing wrong with this but am hoping someone has seen this before. It's fairly straightforward...
Here's my request object:
public class PreferenceRequest
{
[Required]
public int UserId;
public bool usePopups;
public bool useTheme;
public int recentCount;
public string[] detailsSections;
}
Here's my controller method in the UserController class:
public HttpResponseMessage Post([FromBody]PreferenceRequest request)
{
if (request.systemsUserId > 0)
{
TheRepository.UpdateUserPreferences(request.UserId, request.usePopups, request.useTheme,
request.recentCount, request.detailsSections);
return Request.CreateResponse(HttpStatusCode.OK, "Preferences Updated");
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.NotAcceptable, "You must provide User ID");
}
}
Here's my ajax call:
var request = {
UserId: userId,
usePopups: usePopups,
useTheme: useTheme,
recentCount: recentCount,
detailsSections: details
};
$.ajax({
type: "POST",
data: request,
url: "http://localhost:1111/service/User",
success: function (data) {
return callback(data);
},
error: function (error, statusText) {
return callback(error);
}
});
I've tried setting the dataType & contentType to several different things ('json', 'application/json', etc) but the properties of the request object are always defaulted or null. So, for example, if I pass in this object:
var request = {
UserId: 58576,
usePopups: false,
useTheme: true,
recentCount: 10,
detailsSections: ['addresses', 'aliases', 'arrests', 'events', 'classifications', 'custody', 'identifiers', 'phone', 'remarks', 'watches']
}
I can see a fully populated request object with the valid values as listed above. But in the Web API controller, the request is there, but the properties are as follows:
UserId: 0,
usePopups: false,
useTheme: false,
recentCount: 0,
detailsSections: null
FYI - I'm not doing ANY ASP.Net MVC or ASP.NET pages with this project, just using the Web API as a service and making all calls using jQuery $.ajax.
Any idea what I'm doing wrong here? Thanks!
UPDATE: I just want to note that I have many methods in this same Web API project in other controllers that do this exact same thing, and I am calling the exact same way, and they work flawlessly! I have spent the morning comparing the various calls, and there doesn't appear to be any difference in the method or the headers, and yet it just doesn't work on this particular method.
I've also tried switching to a Put method, but I get the exact same results - the request object comes in, but is not populated with the correct values. What's so frustrating is that I have about 20 controller classes in this project, and the Posts work in all of those...
This seems to be a common issue in regards to Asp.Net WebAPI.
Generally the cause of null objects is the deserialization of the json object into the C# object. Unfortunately, it is very difficult to debug - and hence find where your issue is.
I prefer just to send the full json as an object, and then deserialize manually. At least this way you get real errors instead of nulls.
If you change your method signature to accept an object, then use JsonConvert:
public HttpResponseMessage Post(Object model)
{
var jsonString = model.ToString();
PreferenceRequest result = JsonConvert.DeserializeObject<PreferenceRequest>(jsonString);
}
So there are 3 possible issues I'm aware of where the value does not bind:
no public parameterless constructor
properties are not public settable
there's a binding error, which results in a ModelState.Valid == false - typical issues are: non compatible value types (json object to string, non-guid, etc.)
So I'm considering if API calls should have a filter applied that would return an error if the binding results in an error!
Maybe it will help, I was having the same problem.
Everything was working well, and suddently, every properties was defaulted.
After some quick test, I found that it was the [Serializable] that was causing the problem :
public IHttpActionResult Post(MyComplexClass myTaskObject)
{
//MyTaskObject is not null, but every member are (the constructor get called).
}
and here was a snippet of my class :
[Serializable] <-- have to remove that [if it was added for any reason..]
public class MyComplexClass()
{
public MyComplexClass ()
{
..initiate my variables..
}
public string blabla {get;set;}
public int intTest {get;set;
}
I guess problem is that your controller is expecting content type of [FromBody],try changing your controller to
public HttpResponseMessage Post(PreferenceRequest request)
and ajax to
$.ajax({
type: "POST",
data: JSON.stringify(request);,
dataType: 'json',
contentType: "application/json",
url: "http://localhost:1111/service/User",
By the way creating model in javascript may not be best practice.
Using this technique posted by #blorkfish worked great:
public HttpResponseMessage Post(Object model)
{
var jsonString = model.ToString();
PreferenceRequest result = JsonConvert.DeserializeObject<PreferenceRequest>(jsonString);
}
I had a parameter object, which had a couple of native types and a couple more objects as properties. The objects had constructors marked internal and the JsonConvert.DeserializedObject call on the jsonString gave the error:
Unable to find a constructor to use for type ChildObjectB. A class
should either have a default constructor, one constructor with
arguments or a constructor marked with the JsonConstructor attribute.
I changed the constructors to public and it is now populating the parameter object when I replace the Object model parameter with the real object. Thanks!
I know, this is a bit late, but I just ran into the same issue. #blorkfish's answer worked for me as well, but led me to a different solution. One of the parts of my complex object lacked a parameter-less constructor. After adding this constructor, both Put and Post requests began working as expected.
I have also facing this issue and after many hours from debbug and research can notice the issue was not caused by Content-Type or Type $Ajax attributes, the issue was caused by NULL values on my JSON object, is a very rude issue since the POST neither makes but once fix the NULL values the POST was fine and natively cast to my respuestaComparacion class here the code:
JSON
respuestaComparacion: {
anioRegistro: NULL, --> cannot cast to BOOL
claveElector: NULL, --> cannot cast to BOOL
apellidoPaterno: true,
numeroEmisionCredencial: false,
nombre: true,
curp: NULL, --> cannot cast to BOOL
apellidoMaterno: true,
ocr: true
}
Controller
[Route("Similitud")]
[HttpPost]
[AllowAnonymous]
public IHttpActionResult SimilitudResult([FromBody] RespuestaComparacion req)
{
var nombre = req.nombre;
}
Class
public class RespuestaComparacion
{
public bool anioRegistro { get; set; }
public bool claveElector { get; set; }
public bool apellidoPaterno { get; set; }
public bool numeroEmisionCredencial { get; set; }
public bool nombre { get; set; }
public bool curp { get; set; }
public bool apellidoMaterno { get; set; }
public bool ocr { get; set; }
}
Hope this help.
I came across the same issue. The fix needed was to ensure that all serialize-able properties for your JSON to parameter class have get; set; methods explicitly defined. Don't rely on C# auto property syntax! Hope this gets fixed in later versions of asp.net.
A bit late to the party, but I had this same issue and the fix was declaring the contentType in your ajax call:
var settings = {
HelpText: $('#help-text').val(),
BranchId: $("#branch-select").val(),
Department: $('input[name=departmentRadios]:checked').val()
};
$.ajax({
url: 'http://localhost:25131/api/test/updatesettings',
type: 'POST',
data: JSON.stringify(settings),
contentType: "application/json;charset=utf-8",
success: function (data) {
alert('Success');
},
error: function (x, y, z) {
alert(x + '\n' + y + '\n' + z);
}
});
And your API controller can be set up like this:
[System.Web.Http.HttpPost]
public IHttpActionResult UpdateSettings([FromBody()] UserSettings settings)
{
//do stuff with your UserSettings object now
return Ok("Successfully updated settings");
}
In my case problem was solved when i added
get{}set{}
to parameters class definition:
public class PreferenceRequest
{
public int UserId;
public bool usePopups {get; set;}
public bool useTheme {get; set;}
public int recentCount {get; set;}
public string[] detailsSections {get;set;}
}
enstead of:
public class PreferenceRequest
{
[Required]
public int UserId;
public bool usePopups;
public bool useTheme;
public int recentCount;
public string[] detailsSections;
}
As this issue was troubling me for almost an entire working day yesterday, I want to add something that might assist others in the same situation.
I used Xamarin Studio to create my angular and web api project. During debugging the object would come through null sometimes and as a populated object other times. It is only when I started to debug my project in Visual Studio where my object was populated on every post request. This seem to be a problem when debugging in Xamarin Studio.
Please do try debugging in Visual Studio if you are running into this null parameter problem with another IDE.
Today, I've the same problem as yours. When I send POST request from ajax the controller receive empty object with Null and default property values.
The method is:
[HttpPost]
public async Task<IActionResult> SaveDrawing([FromBody]DrawingModel drawing)
{
try
{
await Task.Factory.StartNew(() =>
{
//Logic
});
return Ok();
}
catch(Exception e)
{
return BadRequest();
}
}
My Content-Type was correct and everything else was correct too. After trying many things I found that sending the object like this:
$.ajax({
url: '/DrawingBoard/SaveDrawing',
type: 'POST',
contentType: 'application/json',
data: dataToPost
}).done((response) => { });
Won't work, but sending it like this instead worked:
$.ajax({
url: '/DrawingBoard/SaveDrawing',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(dataToPost)
}).done((response) => { });
Yes, the missing JSON.stringify() caused the whole issue, and no need to put = or anything else as prefix or suffix to JSON.stringify.
After digging a little bit. I found that the format of the request payload completely different between the two requests
This is the request payload with JSON.stringify
And this is the request payload without JSON.stringify
And don't forget, when things get magical and you use Google Chrome to test your web application. Do Empty cache and hard reload from time to time.
I ran into the same issue, the solution for me was to make certain the types of my class attributes matched the json atributes, I mean
Json: "attribute": "true"
Should be treated as string and not as boolean, looks like if you have an issue like this all the attributes underneath the faulty attribute will default to null
I ran into the same problem today as well. After trying all of these, debugging the API from Azure and debugging the Xamarin Android app, it turns out it was a reference update issue. Remember to make sure that your API has the Newtonsoft.JSON NUGET package updated (if you are using that).
My issue was not solved by any of the other answers, so this solution is worth consideration:
I had the following DTO and controller method:
public class ProjectDetailedOverviewDto
{
public int PropertyPlanId { get; set; }
public int ProjectId { get; set; }
public string DetailedOverview { get; set; }
}
public JsonNetResult SaveDetailedOverview(ProjectDetailedOverviewDto detailedOverview) { ... }
Because my DTO had a property with the same name as the parameter (detailedOverview), the deserialiser got confused and was trying to populate the parameter with the string rather than the entire complex object.
The solution was to change the name of the controller method parameter to 'overview' so that the deserialiser knew I wasn't trying to access the property.
I face this problem this fix it to me
use attribute [JsonProperty("property name as in json request")]
in your model by nuget package newton
if you serializeobject call PostAsync only
like that
var json = JsonConvert.SerializeObject(yourobject);
var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json");
var response = await client.PostAsync ("apiURL", stringContent);
if not work remove [from body] from your api
HttpGet
public object Get([FromBody]object requestModel)
{
var jsonstring = JsonConvert.SerializeObject(requestModel);
RequestModel model = JsonConvert.DeserializeObject<RequestModel>(jsonstring);
}
public class CompanyRequestFilterData
{
public string companyName { get; set; }
public string addressPostTown { get; set; }
public string businessType { get; set; }
public string addressPostCode{ get; set; }
public bool companyNameEndWith{ get; set; }
public bool companyNameStartWith{ get; set; }
public string companyNumber{ get; set; }
public string companyStatus{ get; set; }
public string companyType{ get; set; }
public string countryOfOrigin{ get; set; }
public DateTime? endDate{ get; set; }
public DateTime? startDate { get; set; }
}
webapi controller
[HttpGet("[action]"),HttpPost("[action]")]
public async Task<IEnumerable<CompanyStatusVm>> GetCompanyRequestedData(CompanyRequestFilterData filter)
{}
jsvascript/typescript
export async function GetCompanyRequesteddata(config, payload, callback, errorcallback) {
await axios({
method: 'post',
url: hostV1 + 'companydata/GetCompanyRequestedData',
data: JSON.stringify(payload),
headers: {
'secret-key': 'mysecretkey',
'Content-Type': 'application/json'
}
})
.then(res => {
if (callback !== null) {
callback(res)
}
}).catch(err => {
if (errorcallback !== null) {
errorcallback(err);
}
})
}
this is the working one c# core 3.1
my case it was bool datatype while i have changed string to bool [companyNameEndWith] and [companyNameStartWith] it did work. so please check the datatypes.
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 have a C# controller that should make an asyncronous call to another remote controller sending a simple object (model):
HttpClient clientHTTP = new HttpClient();
myModel model = new myModel();
model.Id = 100;
model.data = "this is data";
var json = Newtonsoft.Json.JsonConvert.SerializeObject(model);
clientHTTP.BaseAddress = new Uri("http://REMOTE_IP/");
clientHTTP.PostAsJsonAsync("/WebcastNotify/Heat", json)
.ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
The remote controller:
public class WebcastNotifyController : Controller
{
public ActionResult Heat(myModel model)
{
// allways recieve model.Id = 0 and model.data = null
}
}
And the simple model:
public class modeloWebCast
{
public int Id { get; set; }
public string data { get; set; }
}
Why I getting allways and empty object at remote controller (model.id = 0, model.data=null)
Like peopple suggested, If i pass the model variable directly, I recieve null object (not object with null properties like before) in the controller.
I tried to use a simple html page to test:
function Send()
{
var Url = "#Url.Action("Heat", "WebcastNotify")";
$.ajax(
{
type: "post",
url: Url,
ajaxasync: true,
data: {modelo:{ Id: 100, data: "this is the data"}},
success: function (result) {
$("#CapaInfo").html(result);
}
})
}
And with this code the object is sent to the controller perfectly.
What can i doing wrong?
PostAsJsonAsync() takes an object to serialize as JSON.
You're passing it a string (which happens to be serialized JSON), so it serializes that to a JSON string ("...").
You need to pass it the actual object.
I believe the PostAsJsonAsync method accepts a normally typed value and does not expect it to have already been serialized.
See the MSDN page.
Try passing the model variable directly.
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?
Here's my situation: I have a UserBadge object in ASP.NET, it contains 3 fields, being a User object, a Badge object and a boolean (isNotified) to check if the user has been notified of earning a badge. I'm having issues sending a specific UserBadge from this WebMethod():
[WebMethod()]
public static UserBadge Notify()
{
var db = new achievDb();
foreach (var uB in db.UserBadges)
{
if (System.Web.HttpContext.Current.User.Identity.Name == uB.User.UserName)
{
if (!uB.isNotified)
{
return uB;
}
}
}
return null;
}
to my $.ajax:
<script type="text/javascript">
$(document).ready(function () {
$.ajax({
type: "POST",
url: "../NotifCodeBehind.aspx/Notify",
data: "{}",
complete: function (result) {
if (result) {
$("#notify").jGrowl("You've unlocked a badge!", { header: 'Yay', close: function () {
$.ajax({
type: "POST",
url: "../NotifCodeBehind.aspx/Notified",
data: "{}",
success: function (ub) { DoCallback(JSON.stringify(ub)); },
error: function () { DoCallback("NOPE!") }
});
}
})
};
function DoCallback(msg) {
alert(msg);
}
}
})
})
</script>
and then back to another WebMethod() that sets the isNotified boolean to true once the notification is closed:
[WebMethod()]
public static void Notified(UserBadge ub)
{
var db = new achievDb();
foreach (var userbadge in db.UserBadges)
{
if (userbadge.UserId == ub.UserId && userbadge.BadgeId == ub.UserId)
{
userbadge.isNotified = true;
db.SaveChanges();
}
}
}
The Problem:
I have absolutely no idea how to actually pass the object to the ajax, and then back again... I've spent about 1,5 days browsing the internet about it, but now, I've decided to come for help. The more I read about it, the more it confuses me, and I'm an absolute newbie to jQuery/Ajax/JSON.
So if you could keep it as simple as possible, and nudge me in the right direction, it would be most appreciated!
EDIT:
New JavaScript below, thought I had it, but I didn't.
EDIT2:
This is now solved, I ended up using a controller instead of WebMethods.
You want to work with JSON serialization. When you return the result to your ajax callback method, your web method can return result in form of XML, JSON or string. If you return a JSON, your complex object will be converted to a json object in a very straight forward manner.
Assuming your class structure
class UserBadge
{
User UserProperty { get; set; }
Badge BadgeProperty { get; set; }
bool IsNotified { get; set; }
}
class User
{
string Username { get; set; }
}
Your json object in javascript from the result callback function will look like
{
UserProperty: { Username: "some username" },
BadgeProperty: { /**********/ },
IsNotified: true
}
As you can see, your JSON structure is the same as your class object structure.
So, calling result.UserProperty.Username in javascript is perfectly ok.
Constructing the same object and passing it to another ajax web service will transform the JSON object to the managed class objects.
Edit: You can add the ScriptMethodAttribute to your WebMethod to specify JSON response.
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static UserBadge Notify()
{
}
Do you really want to pass the object to your web method ? Why not pass the ids ( UserId, badgeId etc ) and Build the object in your ajax server page using those Id's if needed. You can pass the Id as the query string values.
var userId=4 // read from some hidden items or somewhere
var badgeid=3 // read from somewhere
$.ajax({
type: "POST",
url: "../NotifCodeBehind.aspx/Notify?uid="+userId+"&bid="+badgeId,
data: "{}",
complete: function (result) {
// rest of the code
EDIT : From the Comment, its clear that it is an ASP.NET MVC App
Since it is an ASP.NET MVC application, You can do model binding. You can serialize your form and send that to the controller action via jquery post.
If your page is having a "LogOnMOdel" and you want to do this binding for the UserBadge object as well, you need to create another ViewModel which has 2 properties , one is LogonModel and another is UserBadge. then pass that view model to your page.
Well, finally figured it out with a little help from my brother and some good old fashioned exercise! I solved the issue by using a controller instead of a code-behind with WebMethods.