How to pass in Uri complex objects without using custom ModelBinders or any serialization?

Do you wonder why I publish such an article?
Well, recently it happened to me to ask to a legacy information system in which I was to find information of users only with their name and their first name…
Yes yes using their name first name:).

I had to send to the WebApi a list of name/first name, the whole paginated, how did I make it?

At the beginning I had the idea to create my search model object in JSON which I would have to serialize while passing it in the URL, then, I had the idea to create an object with a string property containing the list of the names/firstnames the whole “decorated with separators” then split it in the WebAPI with a custom ModelBinder. Finally I decided I’d rather understand how to pass in the Uri more or less complex objects without using of ModelBinder or serialisation?.

Here what I did:

I tested 2 scenarios, the first with a list of “Person” and a second with a little more complex object “ListOfPersons”.
Before starting, as a reminder, I just want to remind you how we pass in a Uri a string collection.

namespace QueryStringDemo.Models
{
    public class Person
    {
        public string FirstName { get; set; }

        public string LastName { get; set; }
    }
}
namespace QueryStringDemo.Models
{
    public class ListOfPersons
    {
        public int? PageNumber { get; set; } 
        public int? PageSize { get; set; }
        public List Persons { get; set; }
    }
}
using QueryStringDemo.Models;
using System.Collections.Generic;
using System.Web.Http;

namespace QueryStringDemo.Controllers
{
    [RoutePrefix("api/demo")]
    public class DemoController : ApiController
    {
        [Route("simplelist")]
        [HttpGet]
        public IHttpActionResult Get([FromUri]List strings)
        {
            return Ok();
        }

        [Route("simplelistOfpersons")]
        [HttpGet]
        public IHttpActionResult Get([FromUri]List listOfPersons)
        {
            return Ok();
        }

        [Route("complexlistOfpersons")]
        [HttpGet]
        public IHttpActionResult Get([FromUri]ListOfPersons listOfPersons)
        {
            return Ok();
        }
    }
}

1- Scenario 1, reminder, string collection :

Uri :

scenario1-url

Result in code :

scenario1-code

Note that you have to use the attribute [FromUri], it provides deserialization to the target object from a complex object that comes from the queryString.

2- Scenario 2, collection of person object :

Uri :

scenario2-url

Result in code :

scenario2-code-1

Note that the object is in fact an array, an array like this

?[index].PropertyName=Value

3- Scenario 3, a more complex collection of person object :

Uri :

scenario3-url

Result in code :

scenario3-code

Note that it works also with an array,
our object looks like this :

?PropertyName1=value&PropertyName2=value&PropertyName3[index].SubPropertyName1=value&PropertyName3[index].SubPropertyName2=value

Finally we have demystified how queryString native serialization/deserialization works, was it so complicated ? 🙂