$http.post angularJS with files. ASP.NET - angularjs

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; }
//..
}

Related

POSTing object from AngularJS to .net WebAPI is always null

I tried everything yet still when debugging the value at the web api post action is always null.
i tried changing the headers, i added [JsonObject(MemberSerialization.OptOut)] above the posted model class, i tried a simple Dto. nothing works...
this is the controller function that passes the user data:
$scope.Add = function () {
var user = {
ID: $scope.ID,
FirstName: $scope.FirstName,
LastName: $scope.LastName,
Age: $scope.Age,
Address: $scope.Address
};
$scope.usersRepo.push(user);
myService.addUser(user);
the service function is:
var addUser = function (user) {
return $http.post(
usersApi + '/addNewUser',
JSON.stringify(user)),
{
headers: {
'Content-Type': 'application/json'
}
};
};
and the web api action is:
[HttpPost, ActionName("addUser")]
public void Post([FromBody]UserModel value)
{
UsersDB.Add(value);
}
my model is this:
[JsonObject(MemberSerialization.OptOut)]
public class UserModel
{
public UserModel()
{
}
public UserModel(string firstName, string lastName, int age, string address)
{
this.Address = address;
this.Age = age;
this.FirstName = firstName;
this.LastName = lastName;
}
public void ConvertDto(UserDto userDto)
{
ID = userDto.ID;
FirstName = userDto.FirstName;
LastName = userDto.LastName;
Age = userDto.Age;
Address = userDto.Address;
}
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string Address { get; set; }
}
Use http post method like this. data should be your object to be passed without json stringify. I advised you to create a service for http methods.
var obj = {
url: your url,
async: true,
method: 'POST',
headers: {
"content-type": "application/json; charset=utf-8",
}
};
if (typeof data != 'undefined' && typeof data != null) {
obj.data = data;
}
$http(obj).then(function() {}, function() {});
Service :
// http methods
app.service('MethodProvider', ['$http', function ($http) {
var self = this;
self.get = function (url, data) {
var obj = {
url: url,
async: true,
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
if (typeof data != 'undefined' && data != null) {
obj.params = data;
}
return $http(obj);
};
self.post = function (url, data) {
var obj = {
url: url,
async: true,
method: 'POST',
headers: {
"content-type": "application/json; charset=utf-8",
}
};
if (typeof data != 'undefined' && typeof data != null) {
obj.data = data;
}
return $http(obj);
};
self.put = function (url, data) {
var obj = {
url: url,
async: true,
method: 'PUT',
headers: {
'Content-Type': 'application/json'
}
};
if (typeof data != 'undefined' && data != null) {
obj.data = JSON.stringify(data);
}
return $http(obj);
};
self.delete = function (url) {
var obj = {
url: url,
async: true,
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
};
if (typeof data != 'undefined' && data != null) {
obj.data = JSON.stringify(data);
}
return $http(obj);
};
}]);

What is causing the model to null

Angular Service:-
app.service('loginService', ['$http', function ($http) {
this.userLogin = function (user) {
console.log(user); //prints {'username': 'username#gmail.com', 'password': 123'}
$http(
{
url: "/api/user/login",
method: "POST",
data: { 'model': user },
contentType: "application/json"
})
.then(function (data) {
if (data.status.toLower() === "success") {
return data;
}
else {
return null;
}
});
}
Angular Controller
app.controller('homeCtrl', ['$scope', 'loginService', function ($scope, loginService) {
$scope.login = function (user) {
debugger;
console.log($scope.user);
var data = loginService.userLogin($scope.user);
}
}]);
WebAPI.
[Route("api/user/login")]
public void Post([FromBody]LoginVM model)
{
if(ModelState.IsValid)
{
}
else
{
}
}
But when I debug the WebAPI model it has all the values as null.
My LoginVM class
[Required]
public string Username { get; set; }
[Required]
public string Password { get; set; }
Why I am getting the properties as null?
Your passing your content type header incorrectly. It get's passed as part of the headers parameter like so:
$http({
url: "/api/user/login",
method: "POST",
data: { 'model': user },
headers: {
"Content-Type": "application/json"
}
}).then(function (data) {
if (data.status.toLower() === "success") {
return data;
} else {
return null;
}
});
However, unless you have changed the default headers you don't even need to pass the content type. See the default headers in the documentation.
So you can simply make your request like so:
$http({
url: "/api/user/login",
method: "POST",
data: {
model: user
}
}).then(function (data) {
if (data.status.toLower() === "success") {
return data;
} else {
return null;
}
});
And you shouldn't need the [FromBody] Attribute on your method because your LoginVM is a complex type (Class).
Also, I've had it in the past where sometimes visual studio plays up and it's not debugging correctly. It's worth closing visual studio and re-opening it if that's the IDE you're using.

Pass a list of objects to MVC action method using AngularJS post

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>

Parameters on controller always null when submitted via Angular

I'm creating a js object with the same properties as my controller action expects as parameters.
controller.js
(function () {
'use strict';
angular
.module('app')
.controller('requestController', requestController);
requestController.$inject = ['$scope', 'lecturesFactory', 'attendeesFactory'];
$scope.setSelectedLectures = function () {
var lecture1, lecture2;
for (var i = $scope.lectures.length - 1; i >= 0; i--) {
var lecture = $scope.lectures[i];
if (lecture.selected === true) {
if (lecture1 == null) {
lecture1 = lecture.lectureId;
}
else {
lecture2 = lecture.lectureId;
}
}
}
attendeesFactory.setSelectedLectures($scope.emailAddress.text, lecture1, lecture2).then(function (data) {
$scope.showInvalidUserMessage = true;
$scope.message = data.message;
});
};
activate();
function activate() { }
}
})();
attendessFactory.js
(function () {
'use strict';
angular
.module('app')
.factory('attendeesFactory', attendeesFactory);
attendeesFactory.$inject = ['$http'];
function attendeesFactory($http) {
var service = {
setSelectedLectures: setSelectedLectures
};
return service;
function setSelectedLectures(emailAddress, lecture1, lecture2) {
var promise = $http({
method: 'POST',
url: '/Home/SetSelectedLectures',
data: {
emailAddress: emailAddress,
lecture1: lecture1,
lecture2: lecture2
}
}).then(function (response) {
console.log(response);
return response.data;
});
return promise;
}
}
})();
And my MVC Controller:
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult SetSelectedLectures(SelectedLectureData data)
{
// ...
}
}
public class SelectedLectureData
{
public String EmailAddress { get; set; }
public int Lecture1 { get; set; }
public int? Lecture2 { get; set; }
}
I've tried what some posts on StackOverflow suggested, such as using JSON.stringify, changing the content-type, but I still get the parameter values null (even if I put them directly in the action, instead of using a custom class).
Use [FromBody] anotation to make it working which will serialize data in SelectedLectureData model.
public IActionResult SetSelectedLectures([FromBody]SelectedLectureData data)
Otherwise you need to do
var promise = $http({
method: 'POST',
url: '/Home/SetSelectedLectures',
data: JSON.strigify({ "data": {
emailAddress: emailAddress,
lecture1: lecture1,
lecture2: lecture2
}})
})
Try updating your javascript to
function setSelectedLectures(emailAddress, lecture1, lecture2) {
var model = {
emailAddress: emailAddress,
lecture1: lecture1,
lecture2: lecture2
};
var data = JSON.strigify(model);
var promise = $http({
method: 'POST',
url: '/Home/SetSelectedLectures',
data: data
}).then(function (response) {
console.log(response);
return response.data;
});
return promise;
}
and using [FromBody] attribute on controller action
[HttpPost]
public IActionResult SetSelectedLectures([FromBody]SelectedLectureData data)
{
// ...
}
JSON property name should be same as class properties else it will take it as null
function setSelectedLectures(emailAddress, lecture1, lecture2) {
var promise = $http({
method: 'POST',
url: '/Home/SetSelectedLectures',
data: {
EmailAddress : emailAddress,
Lecture1: lecture1,
Lecture2: lecture2
}
}).then(function (response) {
console.log(response);
return response.data;
});

POSTing from Angular to .net WebAPI is always null

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 }));
});
}

Resources