This question already has an answer here:
Simple post to Web Api
(1 answer)
Closed 7 years ago.
I am trying to pass data to my web API using JSON objects. Sending a single object does seems to work fine but as soon as I put a second parameter, the second object does not even seems to initialize on the server side?
Please view the code below to see how I am handling the data parameter
[HttpPost("")]
public JsonResult Post([FromBody]Log_Header headerData,
[FromBody]Log_Detail detailData)
{
return Json("Test");
}
Each of the classes above have simple string data, eg of class below:
public class Log_Header
{
public int Id { get; set; }
public string Name{ get; set; }
}
Example of data being sent:
var header = {
Id: 0,
Name: "Test 3",
}
var detail = {
Id: 0,
Desc: "Test 1",
}
$http({
method: 'POST',
url: "api/addLog",
data : {
header: header,
detail: detail
}
})
This is all just demo data.
I have tried sending the data up in few different ways e.g below:
var data = {
Id: 0,
Name: "Test 3",
LogID: 0,
Desc: "Test",
}
But nothing seems to get this working, I'm guessing I am setting up the web API incorrectly?
Overall, the problem is [FromBody]Release_Log_Detail detailData does not receive any data at all and when viewing the object from a breakpoint it appears as null.
if anyone has any ideas please leave a comment or answer below. If you need anymore information from me please ask.
Whatever we post from angular $http, it consider a single object, so we need to read it in a single object on server
we can do like this
[HttpPost("")]
public JsonResult Post([FromBody]PostData data)
{
return Json("Test");
}
class PostData
{
public Log_Header LogHeader { get; set; }
public Log_Detail LogDetail { get; set; }
}
angular post
$http({
method: 'POST',
url: "api/addLog",
data : {
LogHeader : header,
LogDetail : detail
}
})
In the javascript
$http({
method: 'POST',
url: "api/addLog",
data : JSON.stringify({
header: header,
detail: detail
})
})
create a model
public class dataViewModel
{
public string[] header{ get; set; }
public string[] detail{ get; set; }
}
You have create a controller of name api and action name addLog
[HttpPost]
public JsonResult addLog(dataViewModel data)
{
return Json("Test");
}
hope this helps
Related
I have an Angular app that invokes a c#mvc method:
AngularJS:
var data = JSON.stringify({ 'panelists': $scope.arr, 'webId': $scope.webinarId });
//Call the services
$http.post('/Home/CreatePanelists', JSON.stringify(data))
.then(function (response) {
if (response.data)
$scope.msg = 'Post Data Submitted Successfully!';
}, function (response) {
$scope.msg = 'Service not Exists';
});
Contents of data:
{"panelists":[{"name":"ali","email":"ali#email.com"},{"name":"tom","email":"tom#email.com"},{"name":"arthur","email":"arthur#email.com"}],"webId":94395753244}
Added the following Files:
/Models/Home/Panelist.cs
public class Panelist
{
public string name { get; set; }
public string email { get; set; }
}
/Models/Home/Parameters.cs
public class Parameters
{
public IList<Panelist> panelists { get; set; }
public string webId { get; set; }
}
Updated the Controller:
/Controllers/HomeController.cs:
public ActionResult CreatePanelists(Parameters data)
{
System.Diagnostics.Debug.WriteLine(data.webId);
System.Diagnostics.Debug.WriteLine(data.panelists);
return new EmptyResult();
}
By the time when the debugger enters the CreatePanelists method, I added a watch on data, and both, panelists, and webId are null.
I don't understand where the problem resides. When I debug the AngularJS code in Chrome, and get to the step in which the post request is made, I see that the variable data, does have the array of objects with values (as shown above).
Why is the MVC Controller method CreatePanelist is not seeing these values?
If somebody have an idea and would not mind offering it, that would be nice.
Thank you in advance for your help.
Your problem comes from calling JSON.stringify twice. You are already stringifying it when setting the variable data, don't do it a second time in your post.
I have the following setup
HTML
$.ajax({
url: 'Transaction/updateTransaction',
data: saveDataObject,
}).done(function (e) {
// done
});
Which shows in the Network tab that it's sending the correct data
Querystring Parameters
key:2445
transactionDescription:Description Block
transactionToType[0][transactionToTypeKey]:1
transactionToType[0][transactionKey]:2445
transactionToType[0][transactionValue]:51.25
transactionToType[0][transactionTypeKey]:10
transactionToType[1][transactionToTypeKey]:2
transactionToType[1][transactionKey]:2445
transactionToType[1][transactionValue]:10.5
transactionToType[1][transactionTypeKey]:1
Controller
public class TransactionSave
{
public int key { get; set; }
public string transactionDescription { get; set; }
public List<TransactionToTypeSave> transactionToType { get; set; }
}
public class TransactionToTypeSave
{
public int transactionKey { get; set; }
public int transactionToTypeKey { get; set; }
public int transactionTypeKey { get; set; }
public decimal transactionValue { get; set; }
}
public int updateTransaction(TransactionSave transactionSave)
{
}
When doing a breakpoint in updateTransaction I can see transactionSave has all the data (key and description), and the transactionToType list has two items as expected, however, both of these list items, all of the values are 0.
e.g.
key:2445
transactionDescription: Description Block
transactionToType [
transactionToTypeKey:0
transactionKey:0
transactionValue:0
transactionTypeKey:0
], [
transactionToTypeKey:0
transactionKey:0
transactionValue:0
transactionTypeKey:0
]
What am I doing wrong to pass lists inside objects across ajax?
Thanks
It is failing because your ajax call is making a GET request.
If you do not specify the type proeprty when you use $.ajax method, it will make a GET call. For a GET call, the data will be appended as querystring key value items to the url you are making the ajax call to.
When sending a complex object which has child properties of other types, you should consider doing a POST request. query strings has a limit based on the browser. When the request is POST type, the data will be send in the request body.
This should work.
var saveDataObject =
{
key: 124,
transactionDescription:"My desc",
transactionToType: [{
transactionKey: 111,
transactionTypeKey: 164,
transactionValue:23.34
}
]
};
$.ajax({
type:'post',
url: '#Url.Action("updateTransaction","Transactions")',
contentType:"application/json",
data: JSON.stringify(saveDataObject)
}).done(function(e) {
console.log(e);
});
Make sure you marked your action method with [HttpPost] attribute
[System.Web.Mvc.HttpPost]
public ActionResult updateTransaction(TransactionSave transactionSave)
{
return Json(transactionSave);
}
Now it will send "application/json" as the contentType for the ajax request and the json stringified version of the js object will be in the request body. The model binder will be able to map the posted data to your object
This question already has answers here:
Angular2 HTTP Post ASP.NET MVC Web API
(7 answers)
Closed 6 years ago.
I have a WebAPI controller
public class MyController : ApiController
{
[HttpPost]
public SomeResult MyAction(string name, string message)
{
return SomeResult.???;
}
}
I have an angular controller calling this method
$http
.post("/api/My/MyAction", { name: "bob", message: "hello" })
.then(function(xhr) { ... }, function(xhr) { ... });
I get this result
Server Error in '/' Application.
The resource cannot be found.
What did I do wrong?
P.S. It's not the URL...It works when I use HttpGet and append the parameters to the query string.
For more than one attribute for post requests, you can use [FromBody] in your controller and make a ViewModel class. Example:
[HttpPost]
public HttpResponseMessage UpdateNumber([FromBody]UpdateNumberViewModel model)
{
//To do business
return Request.CreateResponse(HttpStatusCode.OK);
}
UpdateViewModel:
public class UpdateViewModel
{
public int Id{ get; set; }
public string Title{ get; set; }
}
Angular:
var model = {
Id: 1,
Title: 'Vai filhão'
}
$http.post('/api/controller/updateNumber/',model).then(function () { alert("OK"); }, function () {alert("something wrong"); });
You can see more details about how web api it works here: https://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
I've faced that problem, if you google there are different ways to solve it. One of the easiest requires to use only one input object in you WebApi controller, so in you case just crate a class
public class InputData {
public string name { get; set; }
public string message { get; set; }
}
Then change your input to the new create object with [FromBody] prefix (maybe not mandatory, see #ADyson comment)
public SomeResult MyAction([FromBody]InputData inputData)
I have following controller:
[HttpPost]
public JsonResult SaveCompensationComponent(int agencyId, CompensationComponentAllData compensationComponent)
{
int? id = _dmsCompensation.SaveCompensationComponent(agencyId, compensationComponent);
return Json(id, JsonRequestBehavior.AllowGet);
}
Definition of the CompensationComponentAllData class:
public class CompensationComponentAllData
{
some properties
...
public CompensationObject CompensationElement { get; set; }
public CompensationObject CompensationBasis { get; set; }
...
some properties
...
}
CompensationObject class:
public class CompensationObject
{
some properties
...
public ActivityData ByActivity { get; set; }
...
some properties
...
}
ActivityData class:
public class ActivityData
{
some properties
...
public List<int> GoalCategories { get; set; }
public List<int> Policies { get; set; }
...
some properties
...
public ActivityData() { }
public ActivityData(CompensationObjectByActivity record) {
...
}
}
In javascript I create appropriate objects and send that through ajax (contentType: 'application/json' and JSON.stringify used before sending data). Everything is correctly sent to server because I executed following code in the controller:
HttpContext.Request.InputStream.Seek(0, SeekOrigin.Begin);
var jsonStringData = new StreamReader(HttpContext.Request.InputStream).ReadToEnd();
And jsonStringData had correct value:
"{\"agencyId\":\"332\",\"compensationComponent\":{\"Id\":431,\"CompensationComponentInfoId\":509,\"AgencyJobPositionId\":\"306\",\"Name\":\"ggggggg44\",\"Description\":\"fdssssssss\",\"CompensationComponentImpactLevelId\":\"1\",\"CompensationProductionTypeId\":\"1\",\"CompensationFrequency\":{\"Id\":\"1\"},\"CompensationDateTypeId\":\"3\",\"EffectiveDate\":\"06/10/2015\",\"BasisDifferentThanElement\":false,\"CompensationElement\":{\"ObjectTypeId\":\"3\",\"ByActivity\":{\"CompensationAttributeId\":\"21\",\"UnitsId\":\"3\",\"PoliciesLevel\":\"Individual Company/Policy\",\"Policies\":[\"572\",\"139\",\"138\"],\"VerificationLevelId\":\"1\"}},\"CompensationBasis\":{\"ObjectTypeId\":\"3\",\"ByActivity\":{\"CompensationAttributeId\":\"21\",\"UnitsId\":\"3\",\"PoliciesLevel\":\"Individual Company/Policy\",\"Policies\":[\"572\",\"139\",\"138\"],\"VerificationLevelId\":\"1\"}},\"CompensationStructureId\":\"2\",\"CompensationRateId\":\"1\",\"FixedValue\":\"10.00\",\"UseChargeback\":false}}"
Now problem is that after binding compensationComponent.CompensationElement.ByActivity.Policies has a null value even though it should be a list with 3 elements.
What makes me even more confused is that in the same time compensationComponent.CompensationBasis.ByActivity.Policies is bound correctly. Also compensationComponent.CompensationElement.ByActivity.GoalCategories is bound correctly too.
EDIT:
This is my ajax call:
$.ajax({
type: type,
url: url,
data: JSON.stringify(data),
success: callback,
error: function (xhr, ajaxOptions, thrownError) {
...
},
contentType: 'application/json',
cache: cache
});
If I remove JSON.stringify and try something as suggested in this post I get error in binding so 500 is just returned.
Please help.
I think that's a little bit strange that you want to receive part of the JSON as method parameters. I think you need to introduce a class for root object:
public class CompensationModel
{
public int AgencyId { get; set; }
public CompensationComponentAllData CompensationComponent { get; set; }
}
And your controller method will take this class as a parameter:
[HttpPost]
public JsonResult SaveCompensationComponent(CompensationModel model)
I suggest you to use services like json2csharp, let's computer does the boring work.
And few comments about JSON that you send. JSON.stringify doesn't change types:
JSON.stringify({a: [1, 2, 3]}) // -> "{"a":[1,2,3]}"
JSON.stringify({a: ["1", "2", "3"]}) // -> "{"a":["1","2","3"]}"
So if you get strings in your JSON that menas that javascript values are of type string. In C# models you expect to have int, so you might consider to convert data in javascript, though MVC is smart enough to convert these values.
I'm working on a little test bed app, where you give the app a note name, sign, and octave, and it spits out the frequency the note should sound at.
I'm having a problem with a JavaScript object that is sent to a server via AJAX. However, it does not map at all to the class on the action.
The sender code is a piece of JavaScript:
$someContainer.on('click', '.raise-pitch', function (e) {
e.preventDefault();
var $line = $(this).parents('.item-line'),
// Cache GUI elements for this line. Not pertinent.
var data = {
'model': {
'NoteName': $noteName.val(),
'Sign': $noteSign.val(),
'Octave': $noteOctave.val()
},
'steps': 1
};
var dataString = JSON.stringify(data);
$.ajax({
type: 'POST',
url: '#Url.Action("AlterPitch", "Home")',
data: dataString,
async: true,
dataType: 'json',
success: function (result) {
// Unimportant things.
}
});
});
In the data object, you can see that I have two things: the model and the steps. The steps determines how far we alter the musical note. I have verified that the values for note name, sign, and octave are making it into the data object. The steps are pre-determined.
The data object, however, maps to a ViewModel on the C# side, which looks like this:
public class NoteViewModel
{
public enum NoteSign
{
Natural,
Sharp,
Flat
}
public string NoteName { get; set; }
public NoteSign Sign { get; set; }
public int Octave { get; set; }
public float Frequency { get; set; }
private static readonly Dictionary<string, float> FrequencyLookup = new Dictionary<string, float>
{
{"C", 16.35f},
{"C#", 17.32f},
{"D", 18.35f},
{"D#", 19.45f},
{"E", 20.60f},
{"F", 21.83f},
{"F#", 23.12f},
{"G", 24.50f},
{"G#", 25.96f},
{"A", 27.50f},
{"A#", 29.14f},
{"B", 30.87f}
};
// Methods...not important for reasons below.
}
...which itself is encapsulated in a unique view model:
public class AlterPitchViewModel
{
public NoteViewModel model;
public int steps;
public NoteViewModel AlterPitch()
{
model.ChangeStep(steps);
return model;
}
}
...or at least it should. I set a break point in my controller method:
[HttpPost]
public ActionResult AlterPitch(AlterPitchViewModel model)
{
return Json(model.AlterPitch(), JsonRequestBehavior.AllowGet);
}
...But the model is null, which leads to a NullReference exception.
the model isn't serializing to an object that gets sent along in this context. Obviously I am still doing something wrong. Question is...what?
This approach has worked for me.
Server Side:
First, create your ViewModel
public class TestViewModel
{
public string Id { get; set; }
public string Description { get; set; }
}
Then, in the Controller:
[HttpPost]
public ActionResult TestingViewModel(TestViewModel udata)
{
// Stuff.
}
Client Side:
function CallTestingViewModel() {
// We create the javascript object based on the
// definition of our C# ViewModel class.
var udata = {
Id: 1,
Description: 'This is a test.'
};
// Calling the C# method via AJAX.
$.when(GenericAjaxCall('Home/TestingViewModel', false, udata)).then(function (result) {
// do stuff
});
}
// Return the AJAX call as a Promise Object
function GenericAjaxCall(controllerUrl, async, clientData) {
return $.ajax({
type: 'POST',
async: async,
url: controllerUrl,
data: JSON.stringify(clientData),
contentType: 'application/json;',
dataType: 'json'
});
}
Hope it helps.
Your HttpPost Method must have one unique parameter which is your ViewModel. My advice: create a viewmodel per post WebMethod.
So here:
public class AlterPitchViewModel
{
public NoteViewModel note { get; set; };
public int Steps { get; set; };
}
And adapt your Javascript accordingly. No need to name your javascript model instance as the parameter in the ASP method -> one object arrives and only one parameter is available so no ambiguity.