I am trying to Post an object from AngularJS to a MVC 5 WebApi Controller, but the value is always null
I can see in Chrome dev tools that the data can be found on the request.
Angular Controller:
$scope.join = function () {
if (!$scope.joinForm.$valid) return;
// Writing it to the server
var payload = $scope.user;
var res = $http.post('/api/some', JSON.stringify( { Data: { payload } }), { header: { 'Content-Type': 'application/json' } });
res.success(function (data, status, headers, config) {
$scope.message = data;
});
res.error(function (data, status, headers, config) {
alert("failure message: " + JSON.stringify({ data: data }));
});
}
MVC 5 API Controller:
public class SomeController : ApiController
{
// POST api/values
public void Post([FromBody]string value)
{
Trace.Write(value);
}
}
If I wrap my object in {Data: {payload}}
{"Data":{"payload":{"symbol":"xxx","amount":12000,"startdate":"2014-05-23T14:26:54.106Z","enddate":"2015-05-23T14:26:54.106Z","interval":"7 minutes"}}}
if I dont wrap it I get:
{"symbol":"xxx","amount":12000,"startdate":"2014-05-23T14:26:54.106Z","enddate":"2015-05-23T14:26:54.106Z","interval":"7 minutes"}
(Visual Studio 2015 is configured to use IISExpress)
Any ideas?
The reason value was null is because the framework's model binder was unable to match the parameter to the data that was sent in the body of the post.
Create a class to store your payload
public class User
{
public string symbol { get; set; }
public int amount { get; set; }
public DateTime startdate { get; set; }
public DateTime enddate { get; set; }
public string interval { get; set; }
}
update controller
public class SomeController : ApiController
{
// POST api/post
public void Post(User user)
{
//consume data
}
}
Angular controller
$scope.join = function () {
if (!$scope.joinForm.$valid) return;
// Writing it to the server
var res = $http.post('/api/some', $scope.user, { header: { 'Content-Type': 'application/json' } });
res.success(function (data, status, headers, config) {
$scope.message = data;
});
res.error(function (data, status, headers, config) {
alert("failure message: " + JSON.stringify({ data: data }));
});
}
Related
Try to use one of this example - Angularjs $http post file and form data
for example this
$scope.createPost = function () {
$http({
method: 'POST',
url: '/api/Blog/create-post/',
headers: {'Content-Type': 'multipart/form-data'},
data: {
Headline: $scope.Headline,
BodyText: $scope.BodyText,
ImgPost: $scope.fileAdress
},
transformRequest: function (data, headersGetter) {
var formData = new FormData();
angular.forEach(data, function (value, key) {
formData.append(key, value);
});
var headers = headersGetter();
delete headers['Content-Type'];
return formData;
}
})
.then(function onSuccess(response){
if(response.data = "Ok"){
$window.location.reload();
}
})
.catch(function onError(response) {
console.log("Error")
});
}
But I have an error in console (Internal Server Error) 500. I deleted header in my post request and it goes to api controller but with null parameters;
If I modify to this case shown below, but with out files it is working good.
$scope.createPost = function () {
$http({
method: 'POST',
url: '/api/Blog/create-post/',
data: {
Headline: $scope.Headline,
BodyText: $scope.BodyText,
},
})
.then(function onSuccess(response){
if(response.data = "Ok"){
$window.location.reload();
}
})
.catch(function onError(response) {
console.log("Error")
});
}
and I have this result
How I must modify my $http.Post that it will works with files?
My PostViewModel
public class PostViewModel
{
[ScaffoldColumn(false)]
public int Id { get; set; }
[ScaffoldColumn(false)]
public string User { get; set; }
[StringLength(100, MinimumLength = 1)]
public string Headline { get; set; }
[StringLength(1000, MinimumLength = 1)]
public string BodyText { get; set; }
[ScaffoldColumn(false)]
public DateTime? Date_Time { get; set; }
public IList<IFormFile> ImgPost { get; set; }
public IList<int> fileAdress { get; set; }
}
First of all check if $scope.fileAdress is set to actual file. In $http call you can set Content-Type header to undefined before transformRequest
$http({
method: 'POST',
url: '/api/Blog/create-post/',
headers: {'Content-Type': undefined }, //set undefined here
data: {
Headline: $scope.Headline,
BodyText: $scope.BodyText,
ImgPost: $scope.fileAdress
},
transformRequest: function (data, headersGetter) {
var formData = new FormData();
angular.forEach(data, function (value, key) {
formData.append(key, value);
});
return formData;
}
})
Also you need to change action parameter attribute to [FromForm] or you can just remove it completely
[HttpPost]
[Route("create-post")]
public async Task<object> PostSaveOnFile(PostViewModel model)
This is enough to make it work. If you need to pass a single file consider updating your model to contain IFormFile instead of IList<IFormFile>
public class PostViewModel
{
//..
public IFormFile ImgPost { get; set; }
//..
}
I have an action method as given below:
[HttpPost]
public ActionResult Ask(Question question)
{
if (ModelState.IsValid)
{
TempData["NewQuestion"] = question;
return RedirectToAction("Submit");
}
return View(question);
}
The Question class definition is given below:
public class Question
{
public int Id { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public string UserId { get; set; }
public List<Tag> Tags { get; set; }
public int Votes { get; set; }
public List<Answer> Answers { get; set; }
public int Views { get; set; }
public DateTime CreationDate { get; set; }
}
The code which I have written to call the above given action method is as given below:
<script>
function questionController($scope, $http) {
$scope.submit = function () {
var data = $.param({
Title: $scope.title,
Body: $scope.body,
Tags: [$.param({ TagName: 'MVC' }), $.param({ TagName: 'WCF' })]
});
var config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
}
};
$http.post('Ask', data, config)
.success(function (data, status, headers, config) {
$scope.PostDataResponse = data;
})
.error(function (data, status, header, config) {
alert(data);
});
};
}
var queApp = angular.module("queApp", []);
queApp.controller("queCtrl", questionController);
</script>
The action method is being called but the Tags member which is a list is received as null. Please let me know what I am doing wrong.
Try changing Content-Type value to application/json
<script>
function questionController($scope, $http) {
$scope.submit = function () {
var data = {
Title: $scope.title,
Body: $scope.body,
Tags: [{ TagName: 'MVC' }, { TagName: 'WCF' }]
};
var config = {
headers: {
'Content-Type': 'application/json;charset=utf-8;'
}
};
$http.post('Ask', data, config)
.success(function (data, status, headers, config) {
$scope.PostDataResponse = data;
})
.error(function (data, status, header, config) {
alert(data);
});
};
}
var queApp = angular.module("queApp", []);
queApp.controller("queCtrl", questionController);
</script>
Below is my angular and Web APi Code.In the post method null is getting passed instead of India
Angular Code:
HWApp.controller('TestCtrl', function ($scope, $http) {
$scope.SendData = function (Data)
{
$scope.whoo = Data;
console.log(Data);
$http({
url: "api/call/firstCall",
dataType: 'json',
method: 'POST',
data: "India",
headers: {
"Content-Type": "application/json"
}
}).success(function (response) {
$scope.whoo = response;
})
.error(function (error) {
alert(error);
});
}
}
);
Web Api Controller
public class CallController : ApiController
{
[HttpGet]
public string firstCallGet( )
{
return "Get";
}
[HttpPost]
public string firstCall([FromBody] string a)
{
return a;
}
}
Your data parameter should be JSON object.
data :{country : "India" }
Define a model class to automatically deserialze into.
Public class CountryViewModel{
Public string Country{get; set;}
}
Web Api controller should be as follows
public class CallController : ApiController
{
[HttpPost]
public string FirstCall( CountryViewModel in)
{
return in.Country;
}
}
I have the following class:
public class SomeArg
{
public int name { get; set; }
}
the POST request sends that data
var requestData = {};
requestData.items = [{ name: 1 }, { name: 2 }];
requestData.logic = "and";
$http.post('SomeAction/',
JSON.stringify(requestData),
{ headers: { 'Content-Type': 'application/json' } }
)
.success(function (data, status, headers, config) {
}).
error(function (data, status, headers, config) {
});
and the WebApi controller's action
[HttPost]
public HttpResponseMessage SomeAction(string logic = null,
[FromUri]
SomeArg[] items = null) { ... }
I can see that all of the arguments are null. Why ?
The API controller POST method should look like this
[HttPost]
public HttpResponseMessage SomeAction(string logic = null,
[FromBody]SomeArg[] items = null) { ... }
And the angular call should not serialize the object. Angular will do it.
$http.post('SomeAction/',
requestData,
{ headers: { 'Content-Type': 'application/json' } }
)
.success(function (data, status, headers, config) {
}).
error(function (data, status, headers, config) {
});
Update: I rechecked item passed to server, i think you should create a single object on the server that encapsulates the data being passed in POST such as
public class ActionData {
public string logic {get;set;}
public SomeArg[] items {get;set;}
}
and use this as a single argument to your Web API function
public HttpResponseMessage SomeAction(ActionData data) { ... }
Please read how parameter binding works in webapi http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
I have one application consist of ASP.Net WebAPI 2 and Web project for which angularJS is used. The Problem is when i call API with parameters, it does not hit. and when send object, it gets hit.
anjularJS Code:
with parameters
$http({
cache: false
, method: 'POST'
, url: 'http://localhost:51341/api/User/UpdateUser'
, data: { userId: $scope.UsersId, fullName: $scope.name }
}).success(function (data, status, headers, config) {
})
.error(function (data, status, headers, config) {
});
Webapi Code
[HttpPost]
public ApiResponse UpdateUser(int userId, string fullName)
{
return this.Response(true, MessageTypes.Success, "User has been saved successfully.");
}
with object
var model = { userId: $scope.UsersId, fullName: $scope.name };
$http({
cache: false
, method: 'POST'
, url: 'http://localhost:51341/api/User/UpdateUser'
, data: model
}).success(function (data, status, headers, config) {
})
.error(function (data, status, headers, config) {
});
webapi code
[HttpPost]
public ApiResponse UpdateUser(User model)
{
return this.Response(true, MessageTypes.Success, "User has been saved successfully.");
}
User class
public class User
{
public int UserId { get; set; }
public string FullName { get; set; }
public int Age { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
}
when call made with parameters, api DOES NOT get hit. but When call made with Object, api GETS hit.
What I missed when call made with parameters ? Help will be truly appreciated.
From WebApi docs:
At most one parameter is allowed to read from the message body. So
this will not work:
// Caution: Will not work!
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }
For other info I suggest to read:
https://damienbod.wordpress.com/2014/08/22/web-api-2-exploring-parameter-binding/
https://stackoverflow.com/a/24629106/3316654