Binding a collection of a complex type with other properties from a query string

Viewed 1328

I am using asp.net core v2.1, I have a controller inheriting from Controller that contains an action with a parameter decorated with FromQuery based on the following model:

public class PagingControl<T>
{
    public ColumnSort[] ColumnSorts { get; set; }

    public T ColumnFilters { get; set; }

    public int Page { get; set; }

    public int PerPage { get; set; }
}

public class ColumnSort
{
    public string Field { get; set; }

    public SortType Type { get; set; }
}

public enum SortType
{
    Asc = 0,
    Desc
}

The generic parameter represents a flat poco with nullable properties that provide well defined columns and values to filter with. The PagingControl<T> model describes all parameters required to implement paging with the action.

The ColumnSorts property is a collection as multiple successive column sorting is possible.

I have read Array or List in query string does not get parsed however if I understand this, I cannot have a single model that accepts all query parameters.

In order to successfully implement the full functionality of paging, all parameters are required. This worked fine when ColumnSorts was not a collection, consistent with single column sorting.

Does anyone know of a workaround with a query string for this scenario?

1 Answers

The issue you described above has already been fixed. In addition, even if it's is not fixed, you could walk around it by [FromQuery(Name="xxx")]. See dougbu's walkaround.

It seems that you're using the [ApiController], I test it with 2.1.302 and 2.1.402, it works flawlessly.

Let's say you want to query against MyColoumnFilter, which will be used as your T ColumnFilters in the PagingControl<T> class :

public class MyColumnFilter
{
    public string FieldA { get; set; }
    public string FieldB { get; set; }
}

and your action method on server side is :

[Route("api/[controller]")]
[ApiController]
public class MyController : Controller
{
    // GET api/values
    [HttpGet]
    public IActionResult Get([FromQuery]PagingControl<MyColumnFilter> pc)
    { 
        return new JsonResult(pc);
    } 

    // ...
}

If you send a request as below :

GET https://localhost:5001/api/my?page=1&perPage=10&columnFilters.fieldA=1&columnFilters.fieldB=2&columnSorts[0].Field=cs1&columnSorts[0].Type=Asc&columnSorts[1].Field=cs2&columnSorts[1].Type=Desc HTTP/1.1

it will work as expected :

enter image description here

The querystring can be divided into 4 parts:

  1. page : an int of 1
  2. perPage : an int of 10
  3. columnFilters : columnFilters.fieldA=1&columnFilters.fieldB=2
  4. columnSorts[] : since the ColumnSorts is an array, we should construct the parameter like columnSorts[0].Field=xx&columnSorts[0].Type=Asc&columnSorts[1].Field=...

As a side note, it will make the querystring rather complicated if you use the GET http method. See Chris Pratt's comment under my another answer.

Related