Bob Tway
Bob Tway

Reputation: 9603

Asp.Net Core MVC - Complex Model not binding on Get Controller action

Got a mismatch somewhere between my View and Controller which is causing the latter to receive a complex object, full of null values.

[HttpGet("find")]
[ProducesResponseType(typeof(PagableResults<UserDetails>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[SwaggerOperation("FindUsers")]
public async Task<IActionResult> FindUsers([FromQuery]FindUsersSearchFilter searchFilters)

And the searchFilters object is defined like this:

public class FindUsersSearchFilter
{
    public int? Page { get; set; }

    public string Username { get; set; }

    public string Firstname { get; set; }

    public string Surname { get; set; }
}

The View is sending the data in a querystring (because it's a get method) like so:

/find?SearchFilters.Page=1&SearchFilters.Firstname=foo&SearchFilters.Surname=bar&SearchFilters.Username=

However, if you debug the controller action the breakpoint is hit but the FindUsersSearchFilter received by the method has a null value for every property.

Things I've tried:

At a loss as to where to go next. Any suggestions as to what I've got wrong?

Upvotes: 1

Views: 921

Answers (1)

Jonathan Alfaro
Jonathan Alfaro

Reputation: 4376

The request is wrong. It should be:

/find?Page=1&Firstname=foo&Surname=bar&Username=

When you prefix all your properties with SearchFilters the binding engine is most likely looking for a nested property like searchFilters.SearchFilters.FirstName.

So removing the prefix should make it work.

If you really need to use that syntax in the query; then create another class like this:

public class SearchFilterContainer
{
    public FindUsersSearchFilter SearchFilters { get; set; } = new FindUsersSearchFilter();
}

And pass that in the action as the parameter instead like this:

[HttpGet("find")]
[ProducesResponseType(typeof(PagableResults<UserDetails>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[SwaggerOperation("FindUsers")]
public async Task<IActionResult> FindUsers([FromQuery]SearchFilterContainer searchFilters)

Then inside your controller you can access the model like this searchFilters.SearchFilters.FirstName

Upvotes: 2

Related Questions