Matt
Matt

Reputation: 1678

MVC Controller Json Serialization of type that implements IEnumerable<T>

I have the following code which represents the results of a paged query.

public class Page<T> : IEnumerable<T>
{
    public IEnumerable<T> Source { get; }
    public int PageNumber { get; }
    public int PageSize { get; }
    public int TotalCount { get; }

    public int TotalPages => TotalCount / PageSize + (TotalCount % PageSize > 0 ? 1 : 0);

    public Page(
        IEnumerable<T> source,
        int pageNumber,
        int pageSize,
        int totalCount)
    {
        Source = source;
        PageNumber = pageNumber;
        PageSize = pageSize;
        TotalCount = totalCount;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return Source.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

And here is an MVC controller method that returns a page of results via the MVC Json Serializer (not the WebAPI serializer).

    [HttpGet, Route("mergeable")]
    public async Task<ActionResult> Mergeable([FromUri] Mergeable.Query query)
    {
        Page<Mergeable.Model> result = await mediator.Send(query);

        return Json(result, JsonRequestBehavior.AllowGet);
    }

When called, the response Json is the array of T. All the paging meta properties (TotalCount, PageNumber, PageSize) are not serialized.

Does the default MVC Json serializer (whatever that is) ignore other properties on an instance of IEnumerable? How can I override this behaviour?

Upvotes: 2

Views: 1549

Answers (2)

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131219

ASP.NET Web API and ASP.NET Core MVC (which also runs on the full framework) use Json.NET. Json.NET will also generate an array from an object that implements IEnumerable.

This code will produce [1,2,3]

var page=new Page<int>(new int[]{1,2,3},1,10,100);
var text=Newtonsoft.Json.JsonConvert.SerializeObject(page);

Json.NET allows you to specify how you want the object to be serialized through attributes like JsonObject or JsonArray. If you add the JsonObject attribute to the Page class it will be serialized to :

{"Source":[1,2,3],"PageNumber":1,"PageSize":10,"TotalCount":100,"TotalPages":10}

ASP.NET MVC still uses the rather old JavaScriptSerializer whose description is :

Json.NET should be used serialization and deserialization. Provides serialization and deserialization functionality for AJAX-enabled applications.

You can configure ASP.NET MVC to use Json.NET as shown in this SO question. If you don't want to do that, you could use Json.NET to serialize to a string and return the string with a JSON content type, eg :

 return Content(JsonConvert.SerializeObject(page), "application/json");

Upvotes: 1

animalito maquina
animalito maquina

Reputation: 2404

It is a Json format limitation, the json format do not support comlex arrays with additional properties.

The json serialization behavior for objects implemeting IEnumerable is to ignore other properties and just serialize from GetEnumerator().

You can use the Source property to get your elements and avoid the Page<T> : IEnumerable<T> implementation.

Upvotes: 0

Related Questions