Passing complex object from angular service to MVC controller - angularjs

I am trying to pass complex object from angular service to MVC controller. Below is the code-:
Angular Controller
$scope.saveData = function () {
var resultData = new Object();
resultData.Name = $scope.Name;
resultData.Address = new Object();
resultData.Address = $scope.Address;
resultData.Address.Contact = $scope.Address.Contact;
var promiseOrganization = AngularService.saveResult(resultData);
promiseOrganization.then(function (result)
{
alert("Saved successfully.");
}
)
}
Angular Service
this.saveResult = function (resultData) {
return $http.post("/Form/SaveData/" + resultData);
}
MVC Controller
[System.Web.Http.HttpPost]
public string SaveData([FromBody] resultData data)
{
//operation to perform
return "Data Reached";
}
When I try passing complex object from Angular service to mvc controller. It gives me null i.e. object becomes null.
Please suggest.

When using the $http.post method you need to pass the data object as the second paramenter. You can read up on it here
So your angular code should look like
$http.post("/Form/SaveData/", data);
You then need a server side representation of the data you are passing the WebApi controller
public class MyCustomObject
{
public string Name { get; set; }
public MyCustomAddress Address { get; set; }
}
public class MyCustomAddress
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string Contact { get; set; }
}
You need to update your WebApi controller code to use the new server side class as the parameter. Note that I am not using the [FromBody] attribute as this link explains you only need to use the [FromBody] attribute when you want to force Web API to read a simple type from the request body(your type is a complex type)
To force Web API to read a simple type from the request body, add the [FromBody] attribute to the parameter
Updated WebApi Controller code without the [FromBody] attribute:
[System.Web.Http.HttpPost]
public string SaveData(MyCustomObject data)
{
//operation to perform
return "Data Reached";
}

Change your post function to something like this,
$http.post('/Form/SaveData/', resultData)
.success(function (data, status, headers, config) {
})
.error(function (data, status, headers, config) {
});

You are wrong in your post command. It should be:
$http.post("/Form/SaveData/",{resultData: resultData});

The problem is you need to add the following header -> 'Content-Type': 'application/x-www-form-urlencoded'
$http.post('/Form/SaveData/', resultData, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}});

Related

Call .NET Core API from AngularJS using $https - 400 Bad Request

I'm trying to call a .NET Core API from AngularJS. In the AngularJS I'm calling the method like this:
$http({
method: 'POST',
url: '/api/message/transaction/' + this.transaction.id,
data: { "transactionJson": "hello"}
})
.then(function (response) {
var r = response;
})
My .NET Core API method is like this:
[Route("~/api/message/transaction/{transactionId}")]
[HttpPost]
public async Task<ActionResult<DeviceEventsTransactionmsg>> PostTransaction([FromBody] string transactionJson)
{
I'm getting a 400 Bad Request response back from the server. How do I fix it?
I realised the type for the parameter must be a type that has a property named TransactionJson, so I need to define a new C# type:
public class TransactionData() {
public string TransactionJson
}
Then in the API method:
[Route("~/api/message/transaction/{transactionId}")]
[HttpPost]
public async Task<ActionResult<DeviceEventsTransactionmsg>> PostTransaction([FromBody] TransactionData transactionJson)
{
getting a 400 Bad Request response back from the server. How do I fix it?
To fix the issue, as your mentioned, one solution is modifying action parameter, like below.
public async Task<ActionResult<DeviceEventsTransactionmsg>> PostTransaction([FromBody] TransactionData transactionJson)
{
//...
//code logic here
TransactionData class
public class TransactionData
{
public string TransactionJson { get; set; }
}
Besides, we can also implement and use a custom plain text input formatter to make PostTransaction action method that accepts a string-type ACTION parameter work well.
public class TextPlainInputFormatter : TextInputFormatter
{
public TextPlainInputFormatter()
{
SupportedMediaTypes.Add("text/plain");
SupportedEncodings.Add(UTF8EncodingWithoutBOM);
SupportedEncodings.Add(UTF16EncodingLittleEndian);
}
protected override bool CanReadType(Type type)
{
return type == typeof(string);
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
{
string data = null;
using (var streamReader = new StreamReader(context.HttpContext.Request.Body))
{
data = await streamReader.ReadToEndAsync();
}
return InputFormatterResult.Success(data);
}
}
Add custom formatter support
services.AddControllers(opt => opt.InputFormatters.Insert(0, new TextPlainInputFormatter()));
Test Result

JSON object not passing as param to webApi PUT method

I’m using Angularjs and asp.net mvc 5 with webApi2.
I’m having some trouble calling a custom PUT method. I’ve done some studying for the past few days, and although I have a decent feel for the situation, I can’t get my JSON object to pass as a parameter for some reason.
Route template:
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
Web api controller and model (shortened for brevity):
public class AttModel
{
public string dc { get; set; }
public string dt { get; set; }
}
[HttpPut]
public IHttpActionResult PutAttendRecord([FromBody]AttModel model)
{
string dc = model.dc;
DateTime dt = Convert.ToDateTime(model.dt);
var record = (from tbl in db.attend_am_y1
where tbl.dc_number == dc && tbl.class_date_am == dt
select tbl).SingleOrDefault();
record.status_am = "z";
db.SaveChanges();
}
Javascript object (angularjs PUT):
$scope.updateRecord = function () {
var stuInfo = {
dc: $scope.student.dc,
dt: $scope.student.dt
};
$http.put("/api/attendance/PutAttendRecord/" + stuInfo)
.then(function (d) {
alert(d.data.dc_number);
});
}
I tried using Newtonsoft without the extra AttModel class, and passing the param as jObject, but I still get a null value exception within the iHttpActionResult method. The data just isn’t making it to my method. Routing issue?
If I manually place values within these variables in the iHttpActionResult, the method works fine.
Assuming you are getting into your call alright,
you want to attach your object in the body
$http.put("/api/attendance/PutAttendRecord/", stuInfo)
.then(function (d) {
alert(d.data.dc_number);
});
and I don't think you need [FromBody] as I believe this is only specified if the function finds it unclear.

$resource save working with multiple parameters

I have the following method in an asp.net MVC controller, which my angular code is trying to call:
[HttpPost]
public JsonResult SaveEducationList(List<InventoryGroupModel> inventoryEduList, int examId)
{
var listOfInventories = _examService.AddEduInventoryGroup(inventoryEduList);
return Json(listOfInventories);
}
My angular code to call this is:
saveEduList: function (inventoryEduList, examId) {
return $resource('/mysite/Setup/SaveEducationList',
{ inventoryEduList: '#inventoryEduList', examId: '#examId' }, {
save: {
method: 'POST',
isArray: true
}
}).save(inventoryEduList, examId);
}
When this angular method is called, I can see in Chrome's debugger that both the inventoryEduList and examId are populated, but whenever the call to the MVC method is made, nothing happens. Fiddler shows that it was calling method just passing in the examId, nothing else. Is there anyway to pass both parameters?
Try following...
create a new class
public class SaveParam {
public List<InventoryGroupModel> InventoryEduList {get;set;}
public int ExamId {get;set;}
}
then
[HttpPost]
public JsonResult SaveEducationList(SaveParam param)
{
var listOfInventories = _examService.AddEduInventoryGroup(param.InventoryEduList );
return Json(listOfInventories);
}
hope this help

How to pass parameters from class to angular $scope

if i have this class:
public class MainMenuModel
{
public MainMenuModel(string transKey, string stateName, string displayUrl, bool hasSubMenu= false,List<SubMenuModel>subMenu=null)
{
TransKey = transKey;
StateName = stateName;
DisplayUrl = displayUrl;
HasSubMenu = hasSubMenu;
SubMenu = subMenu;
}
public string TransKey { get; set; }
public string StateName { get; set; }
public string DisplayUrl { get; set; }
public bool HasSubMenu { get; set; }
public List<SubMenuModel>SubMenu { get; set; }
}
And if i populate that class like this:
MainMenu.Add(new MainMenuModel("MY_TICKETS", "account.tickets", "/account/tickets/"));
MainMenu.Add(new MainMenuModel("TRANSACTION_HISTORY", "account.transactionhistory", "/account/transactions"));
MainMenu.Add(new MainMenuModel("PAYIN","account.payin","/account/payin"));
MainMenu.Add(new MainMenuModel("PAYOUT", "account.payout", "/account/payout"));
MainMenu.Add(new MainMenuModel("TICKET_PAYOUT", "account.ticketpayout", "/account/ticketpayout"));
MainMenu.Add(new MainMenuModel("SETTINGS","default","default",true,
new List<SubMenuModel>(){
new SubMenuModel("PERSONAL_INFORMATION","account.personalinformation","/account/personalinformation"),
new SubMenuModel("NOTIFICATIONS","account.notificationsettings","/account/notifications"),
new SubMenuModel("CHANGE_PASSWORD","account.changepassword","/account/passwordchange"),
new SubMenuModel("GAME_SETTINGS","default","default"),
}));
MainMenu.Add(new MainMenuModel("PROMOTIONS", "default", "default", true,
new List<SubMenuModel>(){
new SubMenuModel("BONUSES","default","default"),
new SubMenuModel("COMPETITIONS","default","default"),
new SubMenuModel("VOUCHER_REDEEM","default","default"),
}));
How can i call this in angular ..and pass it to $scope.something?Any suggestion?
If you need forming page on server - try to serialize this collection and put in on angular controller init
<div ng-controller="SomeController" ng-init="initialize('#Model.ToJson()')">
My recommendation is that you setup WebApi along with your existing ASP.NET MVC layer.
With that being said all you need to do is to implement the Rest services as GETs or POSTs and from your angular a simple invoke with $http :
Server Side
Using Microsoft Web Api Controller class "ValuesController" but it can be any class name which looks like this:
public class ValuesController : ApiController
{
public string Get(int id){ return "value"; }
...
Client Side
In my AngularJS Controller function it gets the value using $http service:
$http({method:'GET',url: '/api/values/1'}).success(function(data){
$scope.value =data;
})
First, you'll need to setup a server endpoint you can reach through ajax, that'll return the MainMenu structure as a JSON response.
Once you have that endpoint setup, there are several ways to get this data into angular, although I think the best way is to create an Angular service to manage this data. Something like this (bear with me, since I don't know the particulars of your project):
angular.module('application').factory('mainMenuService', ['$http', function($http) {
var ServiceInstance = {
_menuItems: [],
_fetchMenuItems: function() {
var self = this;
$http.post('your/server/endpoint').success(function(data, status, headers, config) {
// Clear exisiting items
self._menuItems.length = 0;
// Assuming menu items have been returned as JSON structure
// Add them all into the Service's mainMenu cache
self._menuItems.push.apply( self._menuItems, data.menuItems );
});
},
getMenuItems: function() {
if (!this._menuItems.length) {
this._fetchMenuItems();
}
// No need to wait on async operation because we're using the same array instance,
// and angular will observe this instance and detect when new items are added.
return this._menuItems;
}
};
return ServiceInstance;
}]);
Then, in your Angular controllers use the service:
// Notice how we reference the 'mainMenuService' here, and angular will inject it automatically
angular.module('application').controller('mainMenuController', ['mainMenuService', function (mainMenuService) {
$scope.mainMenuItems = mainMenuSevice.getMenuItems();
}]);
That way you'll decouple the data from the controller, and you can reuse the service in any controller where it's needed.

Angular $http post returning empty data

I'm managing to post to the server OK, I'd like to get the updated data and load it back into the same JSON object, but the data response is null.
$scope.saveDetails = function() {
$http({
method : 'POST',
url : '/service/rest/orders',
data : $scope.orderDetails
})
.success(function(data, status) {
$scope.orderDetails = data;
})
.error(function() {
alert('error');
});
}
Also worth mentioning, that the initial object is being passed from another controller via $rootscope and injected into the local scope.
$scope.orderDetails = $rootScope.newOrder;
Thanks for any help.
Your code looks fine, I would be checking the backend to make sure data is actually being sent. Another option would be to use the chrome inspector and check the response to make sure you are actually getting something back.
It turns out it was returning the whole object and the order was deeper down, I didn't see that in my console at first.
$scope.orderDetails = data.order;
Thanks for all replies.
In case anyone else runs into this, in my case I had a class with a data contract attribute applied:
[DataContract(Namespace = "http://somespace.com")]
And my class members had not been given the [DataMember] attribute. Web API was not returning back the data. I added the [DataMember] attribute and it fixed it.
[DataMember] public int NumberUpdated { get; set; }
[DataMember] public int NumberInserted { get; set; }
[DataMember] public List<ServicesListImport> InvalidRows {get; set;}

Resources