1

When I use the GET API to send a complex JSON format, the backend cannot obtain the data correctly.

This my query string data:

{
    "page": 1,
    "page_size": 10,
    "sortBy": 
    [
        {"key": "reservation_no", "order": "desc"},
        {"key": "pr_no", "order": "desc"},
        {"key": "pr_item", "order": "asc"}
    ]
}

Then it will be converted to this format

?page=1&page_size=11&sortBy[0][key]=reservation_no&sortBy[0][order]=desc&sortBy[1][key]=pr_no&sortBy[1][order]=desc&sortBy[2][key]=pr_item&sortBy[2][order]=asc

My backend can get page and page_size, but sortBy is null.

1 Answer 1

2

CustomQueryParametersBinder:

using complex_json_can_not_bind_successful.Models;
using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace complex_json_can_not_bind_successful
{
    public class CustomQueryParametersBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            var query = bindingContext.HttpContext.Request.Query;

            var pageValue = query["page"].FirstOrDefault();
            var pageSizeValue = query["page_size"].FirstOrDefault();
            var sortByValues = query.Where(q => q.Key.StartsWith("sortBy")).ToDictionary(k => k.Key, v => v.Value.ToString());

            var result = new QueryParameters
            {
                Page = int.TryParse(pageValue, out var page) ? page : 1,
                PageSize = int.TryParse(pageSizeValue, out var pageSize) ? pageSize : 10,
                SortBy = sortByValues
                    .GroupBy(kv => int.Parse(kv.Key.Split('[')[1].Split(']')[0]))
                    .Select(g => new SortOption
                    {
                        Key = g.FirstOrDefault(kv => kv.Key.Contains("key")).Value,
                        Order = g.FirstOrDefault(kv => kv.Key.Contains("order")).Value
                    })
                    .ToList()
            };

            bindingContext.Result = ModelBindingResult.Success(result);

            return Task.CompletedTask;
        }
    }
}

How to use it:

[HttpGet("method2")]
public IActionResult Get2([ModelBinder(BinderType = typeof(CustomQueryParametersBinder))] QueryParameters queryParameters)
{
    return Ok(queryParameters);
}

You can use sample code like this:

enter image description here

[ApiController]
[Route("[controller]")]
public class TestController : Controller
{
    [HttpGet]
    public IActionResult Get([FromQuery] int page, [FromQuery(Name = "page_size")] int pageSize)
    {
        var sortBy = Request.Query
            .Where(q => q.Key.StartsWith("sortBy"))
            .GroupBy(kv => int.Parse(kv.Key.Split('[')[1].Split(']')[0]))
            .Select(g => new SortOption
            {
                Key = g.FirstOrDefault(kv => kv.Key.Contains("key")).Value.ToString(),
                Order = g.FirstOrDefault(kv => kv.Key.Contains("order")).Value.ToString()
            })
            .ToList();

        var queryParameters = new QueryParameters
        {
            Page = page,
            PageSize = pageSize,
            SortBy = sortBy
        };

        // Your logic here
        return Ok(queryParameters);
    }
}

Models:

public class SortOption
{
    public string Key { get; set; }
    public string Order { get; set; }
}

public class QueryParameters
{
    public int Page { get; set; }
    public int PageSize { get; set; }
    public List<SortOption> SortBy { get; set; }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Can I customize IModelBinder to handle this?
@LanLin Updated. Please let me know if it helps.
This method works, thank you!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.