POSTed JSON object ending up with default values in API controller - c#

I'm trying to POST some data to my web API using jQuery's AJAX function, but MVC doesn't serialise it successfully on the other end - it simply leaves the default values for the model. Some seemingly useful answers don't seem to solve my problem, and its not at all complicated, so I'm not sure what's going wrong.
My model:
public class SavedLevel
{
public int ID { get; set; }
public string Data { get; set; }
}
AJAX request:
var postData= {};
postData.ID = 12;
postData.Data = "hello";
$.ajax(
{
url: "api/level/post",
type: "POST",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({data : postData}),
dataType: "json",
success: function (data)
{
//Something
},
error: function (jqXHR, textStatus, errorThrown)
{
//Something
}
});
The API controller.
[Route("api/level/post")]
[HttpPost]
public HttpResponseMessage PostLevel(SavedLevel data)
{
Debug.WriteLine("id : " + data.ID);
Debug.WriteLine("data : " + data.Data);
return new HttpResponseMessage(HttpStatusCode.OK);
}
The request body.
{"data":{"ID":12,"Data":"hello"}}
The Debug console outputs 0 and "" instead of the expected 12 and "hello".
Thanks for reading.
Note: I tried using a dynamic object and doesn't work at all - I can't even check if it's null.

Change your data to:
data: JSON.stringify(postData),
So the request body becomes:
{"ID":12,"Data":"hello"}
The C# is expecting the SavedLevel object, but you are sending the object wrapped in another object.

Related

Using Ajax to POST to ASP.Net controller - Data for Post incorrect

This is my DisputeController method stub:
[HttpPost]
public virtual ActionResult UpdateDisputeStatus(DisputeUdpateStatusModel model)
{//some code
Here is my Ajax call:
var url = '/dispute/UpdateDisputeStatus';
var disputeStatusObj = {
DisputeId: id,
DisputeStatusId: selectedValue
}
$.ajax({
url: url,
cache: false,
type: 'POST',
contentType: "application/json; charset=utf-8",
data: disputeStatusObj,
success: function (data) {
alert('Status Changed Successfully');
},
error: function (e) {
alert('Error: ' + e.status);
}
});
I know the routing works, as without using the data parameter the code enters my method (obviously without the model in parameters)
I have tried the following data formats:
data: {'DisputeId': DisputeId, 'StatusId': DisputeStatusId},
data: {disputeStatusObj},
data: JSON.Stringify(disputeStatusObj)
using controller methods:
[HttpPost]
public virtual ActionResult UpdateDisputeStatus(string disputeId, string statusId)
[HttpPost]
public virtual ActionResult UpdateDisputeStatus(modelname model)
None of which work. I get Not found errors or 500's.
Bearing in mind that I know the routing is correct, when I send the request with no data, so what am I missing here?
Am I declaring the controller incorrectly?
Verify your model that should be the same name as well as the data type because of while post the value from Jquery that values are not mapping with the property of the model.
#Mike I tried below code
public class DisputeUpdateStatusModel
{
public string DisputeId { get; set; }
public string DisputeStatusId { get; set; }
}
public class DisputeController : Controller
{
[HttpPost]
public virtual ActionResult UpdateDisputeStatus(DisputeUpdateStatusModel model)
{
return new ContentResult() { Content = "OK" };
}
}
script on view as:
<script type="text/javascript">
var disputeStatusObj = {}
disputeStatusObj.model = {
DisputeId: 1,
DisputeStatusId: 1
}
var url = '/dispute/UpdateDisputeStatus';
$.ajax({
url: url,
cache: false,
type: 'POST',
contentType: "application/json; charset=utf-8",
data: JSON.stringify(disputeStatusObj),
success: function (data) {
alert('Status Changed Successfully');
},
error: function (e) {
alert('Error: ' + e.status);
}
});
</script>
Please see.
If this is not working, can you please show Model class?
thanks for all your input. My solution was a combination of the answers above.
I was unable to get my code to model bind, so I went back to basics.
I took out the contentType: "application/json; charset=utf-8", as suggested by Stephen Muecke, and ditched the model in my controller and replaced it with string disputeId, string statusId and as suggested by Er Pravin Suthar ensured the parametes were called the same thing. Also to note, the data section was sent as data: { disputeId: disputeId, statusId: statusId } with no quotes around the parameter names. So I ended up with:
var statusId = statusDropdown.value;
var disputeId = $("#disputeId").val();
$.ajax({
url: "/Dispute/UpdateDisputeStatus",
data: { disputeId: disputeId, statusId: statusId },
type: 'POST',
success: function (data) {
alert('Success');
},
error: function (e) {
alert('Status not changed' + e.responseText + ' : ' + e.status);
}
});
and the Controller structure is:
[HttpPost]
public virtual ActionResult UpdateDisputeStatus(string disputeId, string statusId)
Thanks Again for all your input!

AJAX call not returning JSON object from WebMethod

I am able to make it work (success callback).
But what i get in response is the whole HTML of default.aspx
The AJAX:
function CreateLottery(lottery) {
debugger; // 'lottery' comes with the properties of the Lottery class
$.ajax({
type: 'POST',
url: 'default.aspx/Create',
data: JSON.stringify({ data: lottery }),
dataType: 'text',
success: function (data, status) {
alert(data.TotalValue + " " + status) //"undefined success"
},
error: function () {
alert("error!")
}
});
}
I get "undefined success" in the alert. "data" is the whole html document, not a "Lottery" object.
The Create WebMethod and the Lottery class:
[WebMethod]
public static Lottery Create(Lottery lottery)
{
return lottery;
}
public class Lottery
{
public string TotalValue { get; set; }
public string Players { get; set; }
}
I can't figure out what is going on, the WebMethod is returning exactly the same object that it received, how i can't access it on the success callback?
EDIT: The WebMethod is not being hit. The "ScriptManager" is present in default.aspx with EnablePageMethods set to true. If i change the WebMethod name (Create) to anything and keep /Create in AJAX url still get the whole default.aspx HTML in response.
I think there are two things you'll have to consider:
First of all: You'll have to correct the content type header. It should be application/json instead of text.
The other issue is that [WebMethod] expects XML. It doesn't handle JSON out of the box.
To let your WebMethod return its contents formatted as JSON, you'll have to additionally decorate it as ScriptMethod.
That attribute allows you to specify the format of the response as JSON.
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static Lottery Create(Lottery lottery)
{
// ...
}
Well, but there's one thing I'm not sure about: While you can specify the ResponseFormat I don't see a way to specify the RequestFormat. I assume it accepts JSON as request-type when you define it as response-type. But well, that's just an assumption. Give it a try ;-)
We can't tell why it is not working for you, but perhaps you could try another approach. [WebMethod] is pretty hacky in my opinion, and apparently more complicated than in needs to be. You could add a WebAPI service to your project, but if you want to stick with "old school" web forms then you can implement an IHttpHandler as an ashx file that is a "web service". Note that .aspx pages also implement IHttpHandler but they are designed to return HTML while handlers are meant for generic request handling like file downloads, and data like xml and json.
Implement something like this with the Handler item template and hit it with your ajax call:
using System.IO;
using System.Web;
namespace WebApplication1
{
public class LotteryHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "application/json";
using (var reader = new StreamReader(context.Request.InputStream))
{
string values = reader.ReadToEnd();
//Use Newtonsoft to deserialize to Lottery type
//do whatever with Lottery
//Use Newtonsoft to serialize Lottery again (or whatever you want to return)
context.Response.Write(your_serialized_object);
//finish the response
context.Response.Flush();
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
**old code **
$.ajax({
type: 'POST',
url: 'default.aspx/Create',
data: JSON.stringify({ data: lottery }),
dataType: 'text',
success: function (data, status) {
alert(data.TotalValue + " " + status) //"undefined success"
},
error: function () {
alert("error!")
}
});
**New code **
see the content type and datatype change here
$.ajax({
type: 'POST',
url: 'default.aspx/Create',
data: JSON.stringify({ data: lottery }),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data, status) {
alert(data.TotalValue + " " + status) //"undefined success"
},
error: function () {
alert("error!")
}
});

How can send int and string with ajax to C#

I need post two argument to method in C#
[HttpPost]
public bool information([FromBody]int idInfromation,[FromBody] string information)
{
.....
return true;
}
with ajax, but my solution doesn´t work. Newtwork tab is showing:
POST http://-----/information/SubmitAnswer 500 (Internal Server Error)
I have this:
var source = { "idInfromation": 5, "information": "Wau" };
$.ajax({
url: "/information/",
type: "POST",
data: source,
dataType: "json",
contentType: "application/json",
success: function (data) {
alert("Complete");
}
});
Thank you for your advice.
You can't pass multiple [FormBody] parameters instead you have to pass parameter as an object.
for example, declare a DTO class
// DTO
public class InformationClass{
public int idInfromation{ get; set; }
public string Information{ get; set; }
}
[HttpPost]
public bool information(InformationDTO Info)
{
.....
return true;
}
to pass object using Json ajax:
// Initialize the object, before adding data to it.
// { } is declarative shorthand for new Object().
var Information= { };
Information.idInfromation= ParseInt($("txtId").val()); // your desired value
Information.Information= $("#Information").val();
// Create a data transfer object (DTO) with the proper structure.
var DTO = { 'Information' : Information};
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "InformationService.asmx/information", // or your specified url, if you don't want //use service like url: "/information/",
data: JSON.stringify(DTO),
dataType: "json"
});
Hope this helps,
Thanks.
You can't return two values with [FromBody]. Either create a DTO class or receive it as a JObject.

AJAX & Web Api Post Method - How does it work?

I am trying to write to my database using AJAX / Jquery and c#. Whenever I pass the parameter in to the C# code it shows as null. I am using the default template that visual studio generates when creating a controller class. Any help would be appreciated!
NOte: This is a rest service that I am trying to call. (A regular ASP website... not MVC. Also, the GET Rest api works perfectly.)
Jquery/AJAX:
var dataJSON = { "name": "test" }
$('#testPostMethod').bind("click", GeneralPost);
function GeneralPost() {
$.ajax({
type: 'POST',
url: '../api/NewRecipe',
data:JSON.stringify(dataJSON),
contentType: 'application/json; charset=utf-8',
dataType: 'json'
});
}
C#
//If I remove the [FromBody] Tag then when I click the button this method is never called.
public void Post([FromBody]string name)
{
}
EDIT:
I have adjusted my code slightly but am still encountering the same issue. To recap, It is loading the POST method, but it is passing in null.
C#
public class RecipeInformation
{
public string name { get; set; }
}
public void Post(RecipeInformation information)
{
}
AJAX:
var dataJSON = { information: { name: "test" } };
$('#testPostMethod').bind("click", GeneralPost);
console.log(dataJSON);
function GeneralPost() {
$.ajax({
type: 'POST',
url: '../api/NewRecipe',
data: dataJSON,
contentType: 'application/json; charset=utf-8',
});
}
For simple type, on server side:
public void Post([FromBody]string name)
{
}
on the client side, you just define if you want to send in json format:
var dataJSON = "test";
$('#testPostMethod').bind("click", GeneralPost);
function GeneralPost() {
$.ajax({
type: 'POST',
url: '/api/NewRecipe',
data: JSON.stringify(dataJSON),
contentType: 'application/json; charset=utf-8',
dataType: 'json'
});
}
If you want to make it work in complex type, from server side you should define:
public class RecipeInformation
{
public string name { get; set; }
}
public class ValuesController : ApiController
{
public void Post(RecipeInformation information)
{
}
}
And from client side:
var dataJSON = { name: "test" };
$('#testPostMethod').bind("click", GeneralPost);
function GeneralPost() {
$.ajax({
type: 'POST',
url: '/api/NewRecipe',
data: JSON.stringify(dataJSON),
contentType: 'application/json; charset=utf-8',
dataType: 'json'
});
}
You can try doing something like this and use the jquery param method
var postData = {
name : 'name'
}
$('#testPostMethod').bind("click", GeneralPost);
function GeneralPost() {
$.ajax({
type: 'POST',
url: '../api/NewRecipe',
data: $.param(postData,true),
contentType: 'application/json; charset=utf-8',
dataType: 'json'
});
}
I suppose that you are using ASP.NET WebAPI and it bind all simple types (int, bool, string, etc) from URL and all complex types from body. When you marked name with FromBody attribute then it bind it from request body instead of url mapping.
You can read more about ASP.NET WebAPI routing and parameter binding here:
On www.asp.net
On www.west-wind.com
and on MSDN
There's a piece you're missing is the data contract attributes
If you make a your class like:
[DataContract]
public class RecipeInformation
{
[DataMember]
public string name { get; set; }
}
These attributes are found in System.Runtime.Serialization, and the Json parser (Json.NET) uses them to (help) deserialize the model.
Binding in API controllers is a little on the strange side. I believe:
public void Post([FromBody]RecipeInformation information)
with
var dataJSON = { name: "test" };
should work, and will definitely work if you just pass it as form data.
I found the problem with help from Microsoft Docs
Use JS code as mentioned
$.post('api/updates/simple', { "": $('#status1').val() });
What I missed was adding empty property name, so what OP needs to do is{"":data:JSON.stringify(dataJSON)}, instead of data:JSON.stringify(dataJSON),
$("#updateuser").click(function ()
{
var id = $("#id").val();
var dataJSON = $("#username").val();
alert("" + dataJSON);
$.ajax({
url: 'http://localhost:44700/api/Home/' + id,
type: 'PUT',
data: JSON.stringify(dataJSON),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (data, textStatus, xhr) {
$.each(data, function (key, val) {
$("<li>" + val + "</li>").appendTo($("#names"));
})
},
error: function (xhr, textStatus, errorThrown) {
alert('Error in Operation');
}
})
})

Having trouble passing Javascript array of objects to MVC3 controller, works with WCF service, any ideas?

I am having problems passing a javascript array to an MVC3 controller, not sure what I am doing wrong but this code does work with standard WCF service.
$(function () {
$("button").click(function () {
Poster();
});
});
function Poster() {
var data = [];
data.push(new WidgetProperty("test1", "value1"));
alert(data.length);
$.post("Home/Test", {test : data});
}
function WidgetProperty(name, value) {
this.Name = name;
this.Value = value;
}
and controller is
[HttpPost]
public ActionResult Test(WidgetProperty[] test)
{
return View("About");
}
public class WidgetProperty
{
public string Name { get; set; }
public string Value { get; set; }
}
Any ideas why the object that comes to the controller has null values for the properties? Checked with fiddler and it appears it passing the correct values.
Thanks!
You should use JSON.stringify() on your data before you post it, and since you know the data type is JSON, it is best to specify that the data being posted is JSON.
$.post("Home/Test", {test : JSON.stringify(data) }, "json");
Live DEMO
Edit:
I researched this a little more and it seems that you need to include contentType: "application/json" in order for this to work in mvc3:
$.ajax({
type: "POST",
url: "Home/Test",
data: JSON.stringify(data),
success: function(data){},
dataType: "json",
contentType: "application/json"
});

Categories