0

I'm working on some demo examples on how to pass the form data from an Angular Service to a Web API 2 controller POST action. But my object is always null on the controller side. Here is how my code looks like

AngularJS Call to Web API

$http({
            method: 'POST',
            url: MyApp.rootPath + 'api/CustomerSpaSilo/SearchCustomers?nameFilter=' + nameFilter,
            data: $.param({ '': pagingVM }),
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        });

The pagingVM is an angular $scope object that contains paging details - SortBy, CurrentPage, ItemsPerPage, SortDesc.

My Web API POST method

[HttpPost]
        [Route("SearchCustomers")]
        public HttpResponseMessage Post(string nameFilter, [FromBody] PagingViewModel pagingVM)
        {
            if (nameFilter == null)
                nameFilter = "";

            //Code Implementation
        }

The PagingViewModel class

public class PagingViewModel
    {
        public string SortBy { get; set; }

        public bool SortDesc { get; set; }

        public int CurrentPage { get; set; }

        public int TotalItems { get; set; }

        public int ItemsPerPage { get; set; }

        public int TotalPages
        {
            get {
                if (this.ItemsPerPage > 0)
                    return (int)Math.Ceiling((decimal)TotalItems / this.ItemsPerPage);
                else
                    return 1;  
            }
        }
    }

The pagingVM parameter is always coming as default object. A quick look in the Chrome's network activity shows that all the values are being passed in the request body as the form data. If I change the parameter type to FormDataCollection, then I can read the values and build my object but I'm looking to Web API bind the incoming request values for me. Am I missing something here?

enter image description here

Vivek N
  • 991
  • 12
  • 22

2 Answers2

1

controller

    [RoutePrefix("api/CustomerSpaSilo")]
    public class CustomerSpaSiloController : ApiController
    {
        [HttpPost]
        [Route("SearchCustomers")]
        public IHttpActionResult Post(string nameFilter, [FromBody] PagingViewModel pagingVM)
        {
            if (nameFilter == null)
                nameFilter = "";

            //Code Implementation

            return Ok("Result=" + pagingVM.ToString());
        }
    }

model

    public class PagingViewModel
    {
        public string SortBy { get; set; }

        public bool SortDesc { get; set; }

        public int CurrentPage { get; set; }

        public int TotalItems { get; set; }

        public int ItemsPerPage { get; set; }

        public int TotalPages
        {
            get
            {
                if (this.ItemsPerPage > 0)
                    return (int) Math.Ceiling((decimal) TotalItems/this.ItemsPerPage);
                else
                    return 1;
            }
        }

        public override string ToString()
        {
            return string.Format("PagingViewModel(SortBy='{0}',SortDesc='{1}', CurrentPage='{2}', TotalItems='{3}', ItemsPerPage='{4}')",
                SortBy, SortDesc, CurrentPage, TotalItems, ItemsPerPage);
        }
    }

postman screenshot

enter image description here

js client

<!DOCTYPE html>
<html ng-app="app">
<head>
    <title>Home</title>
</head>
<body ng-controller="HomeController">

<button ng-click="post()">post</button>
<p>{{status}}</p>
<pre>{{result | json}}</pre>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<script>
    (function() {
        'use strict';

        console.trace('js loaded');

        angular
            .module('app', [])
            .factory('api', apiFactory)
            .controller('HomeController', HomeController);

        function apiFactory($http) {
            var svc = {
                searchCustomers: searchCustomers
            };
            return svc;

            function searchCustomers(nameField, paging) {
                return $http
                    .post('/api/CustomerSpaSilo/SearchCustomers?nameFilter=' + nameField,
                        paging,
                        {
                             headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                             transformRequest: function (obj) {
                                 var str = [];
                                 for (var p in obj)
                                    str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
                                 return str.join("&");
                             }
                        }
                     );
            }
        }

        function HomeController($scope, api) {

            console.trace('HomeController');

            $scope.status = null;
            $scope.result = null;
            $scope.post = function () {

                var paging = {
                    SortBy: 'abc',
                    SortDesc: false,
                    CurrentPage: 3,
                    TotalItems: 52,
                    ItemsPerPage: 10
                };

                api.searchCustomers('ddd', paging)
                    .then(function(response) {
                        $scope.status = 'OK';
                        $scope.result = response.data;
                    }, function(reason) {
                        $scope.status = 'Error';
                        $scope.result = reason;
                    });
            };
        }
    })();
</script>
</body>
</html>

chrome screenshot

enter image description here

Ali
  • 1,982
  • 1
  • 15
  • 16
  • Thanks for the answer. I will try and let you know how it goes. – Vivek N Apr 12 '16 at 15:11
  • The postman part works. It's little helpful. But the js client part is not working. The request payload look like {"SortBy":"abc","SortDesc":false,"CurrentPage":3,"TotalItems":52,"ItemsPerPage":10} which is not right. Are you sure the js client is working for you? – Vivek N Apr 12 '16 at 16:33
  • I passed the data as data: $.param(pagingVM) and it seem to have worked. Thanks for the answer, it helped me. I'm still interested in knowing if your js client code is working as expected for you. – Vivek N Apr 12 '16 at 17:07
  • 1
    You are right. I added transformRequest param to $http. http://stackoverflow.com/questions/24710503/how-do-i-post-urlencoded-form-data-with-http-in-angularjs/24964658#24964658 – Ali Apr 13 '16 at 08:56
0

you should use your $http service like as -

 $http.post(MyApp.rootPath + 'api/CustomerSpaSilo/SearchCustomers?nameFilter=' + nameFilter, pagingVM ).then(function (result) {
              //success
                }, function (data) {
               //faild
                }); 
  • It did not work either. The request payload look like {"pagingVM":{"SortBy":"CustomerID","SortDesc":false,"CurrentPage":2,"TotalItems":13,"ItemsPerPage":10,"TotalPages":2}} . Moreover I want to send my data as form data. – Vivek N Apr 12 '16 at 13:57