1

Web API not populating parameter object After researching a number of articles (most specifically: Complex type is getting null in a ApiController parameter but others as well) I have arrived at the following code to pass an object parameter from an AngularJS $Resource factory to ASP.NET Web API (C#) controller. (ultimately the search object will be more complex, but I have reduced the number of properties for simplicity)

The Model:

public class SearchModel
{
    public long ClientId { get; set; }
    public string EmployeeName { get; set; }
    public string FromDate { get; set; }
    public string ToDate { get; set; }
}

The AngularJS Factory

(function () {
    'use strict';
    angular
        .module('mainApp')
        .factory('searchService', searchService);
    searchService.$inject = ['$resource', 'baseApiUrl'];

    function searchService($resource, baseApiUrl) {
        return $resource(baseApiUrl + "api/Search", null, {
            query: { method: "Get", url: baseApiUrl + "api/Search/Get:searchModel", params: { searchModel: '@searchModel' }, isArray: true }
        });
})
();

When executed this code results in this URI: https://localhost:44300/api/Search/Get?clientId=4&fromDate=3%2F1%2F2016&EmployeeName=Bob&toDate=3%2F30%2F2016

The request IS routed to the following SearchController:

[RoutePrefix("api/Search")]
public class SearchController : BaseController
{
//this c’tor contains all the necessary code to implement ninject bindings etc.
    public SearchController(…): base(…)
 {…}
 #if !DEBUG
    [Authorize]  //note: this allows me to execute from Fiddler w/o an auth token
 #endif
    [HttpGet]
    [Route("{searchModel}")]
    public IHttpActionResult Get([FromUri] SearchModel searchModel)
    {
        try
        {
           //Here is where I am breaking the execution to test the results:
           // search model “Is” (not null) but all properties of object ARE null strings or 0 (the long)
            var result = _searchQuery.Get(searchModel);
            return this.GetResult(result);
        }
        catch (Exception ex)
        {
            return InternalServerError(ex);
        }
    }
}

When I enter breakmode at the point noted above the immediate window tells me that the “Request” query string is complete as expected…

Why are my passed values NOT being populated in the SearchModel object of the controller.

[EDIT: after accepted answer I needed to add the angular controller to get to a working solution]

The Controller

(function () {
'use strict';

angular
    .module('mainApp')
    .controller('SearchController', SearchController);

SearchController.$inject = ['$filter', 'searchService'];

function SearchController($filter, searchService) {
    var vm = this;
    vm.searchModel = {
        fromDate: "3/1/2016",
        toDate: "3/30/2016",
        clientId: 4,
        employeeName: "Bob"
    }
    vm.data = searchService.query(vm.searchModel);
}})();

(note that 'next' I plan to use binding to populate these values...but that I expect to achieve easily...well except for the dates...)

Community
  • 1
  • 1
Cos Callis
  • 5,051
  • 3
  • 30
  • 57
  • I think you shouldn't have `[Route("{searchModel}")]` which would expect variable with name `searchModel`, It should be `[Route("")]` to make it working – Pankaj Parkar Mar 30 '16 at 19:23
  • yes, it does 'expect' the variable searchModel...that is what I want. The searchModel variable is, indeed, present...but not populated with the values from the URI as I am expecting...but not getting. – Cos Callis Mar 30 '16 at 19:29
  • sorry to ask you again, but did you tried what I suggested? – Pankaj Parkar Mar 30 '16 at 19:32
  • can you try to change the object SearchModel to a dynamic type to see what is receiving the controller? because when an object remains empty on the controller side its because it cannot assign the values. i think it have something to do with the /Get you are using at the beginning of the query – ShinyDarkStone Mar 30 '16 at 19:37
  • @PankajParkar, yes just to be sure...I know I'm missing something here. Without that Route attribute the request is rejected with a 500 error. – Cos Callis Mar 30 '16 at 19:38
  • @ShinyDarkStone, To be sure I understand your suggestion: I altered the Get to look like `public IHttpActionResult Get([FromUri] dynamic searchModel)` The result is that searchModel becomes a string of value "Get". – Cos Callis Mar 30 '16 at 19:47
  • yes, that was what i wanted, so, thats why is not completing your object because you are sending only a string with get value, the controller do not know what to do with the string value. Try this [Route("Get")] and left the searchObject as dynamic, check if it assign the values you need, after that change, if it does, return to the SearchModel and try. I'm not sure if the get parameters are case sensitive. English is not my primary language, so if you don't understand something do not hesitate on asking – ShinyDarkStone Mar 30 '16 at 19:59
  • Changing Route to `[Route("Get")]` just makes searchModel an empty object. (thanks for your continued efforts) – Cos Callis Mar 30 '16 at 20:04

1 Answers1

3

If you want your query string parameters to bind to a complex object you will need to prefix each query parameter with the name of the parameter in your handling controller method.

In your case:

https://localhost:44300/api/Search/Get?searchModel.clientId=4&searchModel.fromDate=3%2F1%2F2016&searchModel.EmployeeName=Bob&searchModel.toDate=3%2F30%2F2016
Amith Sewnarain
  • 655
  • 6
  • 11
  • We have a winner...Thanks so much. Now please, how do I make sure that my Angular Controller, which calls the factory/service method serializes this correctly.. (I will edit in the controller code shortly) – Cos Callis Mar 30 '16 at 20:09