Search code examples
c#asp.net-web-apiodata

Web API OData v4 $count=true is ignored


I started a new web api project and am using the latest OData libraries but I cannot get the $count to work the way it did in the previous 3.0 version of the odota libraries. No matter what I have tried I am always getting back the array of json objects without it being contained in an object that should have the count of the total number of items in the original unfiltered/sorted collection.

Almost everything else works as expected, I can use $filter, $top, $skip, and $orderby. I have not tried anything else (yet). I have also tried returning a hard coded list of entities instead of the DbSet<Company> but this did not make any difference.

Can anyone tell me what I need to do to get this to work? Bellow is the all the code necessary for a repo, I am only showing the revelant code (at least what I think is the relevant code). If there is anything else I need to show please ask.

packages.config

<package id="Microsoft.AspNet.WebApi" version="5.2.3" />
<package id="Microsoft.AspNet.OData" version="6.0.0" />
<package id="Microsoft.OData.Core" version="7.0.0" />
<package id="Microsoft.OData.Edm" version="7.0.0" />

Company Model

public sealed class Company {
    public int CompanyId { get; set; }
    public string Name { get; set; }
    public CompanyState State { get; set; } // a simple int enum
    public DateTime CreatedOn { get; set; }
}

WebApiConfig.cs

public static void Register(HttpConfiguration config) {
    config.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
    config.MapODataServiceRoute("odata", "odata", GetModel());
}
public static IEdmModel GetModel() {
    var builder = new ODataConventionModelBuilder();
    builder.EnableLowerCamelCase();
    var companySet = builder.EntitySet<Model.Company>("Company").EntityType.HasKey(x => x.CompanyId);
    return builder.GetEdmModel();
}

CompanyController.cs

[ODataRoutePrefix("Company")]
public sealed class CompanyController : ApiController {
    private DbContext context;
    public CompanyController(DbContext context) {
        this.context = context;
    }

    [EnableQuery] // also tried with [EnableQuery(MaxNodeCount = 50, MaxTop = 100, PageSize = 100)]
    [ODataRoute]
    [HttpGet]
    public IHttpActionResult Get()
    {
        return Ok(context.Set<Company>());
    }
}

Test URL

http://localhost:35743/odata/Company/?$count=true&$top=3

Results

[{"companyId":2,"name":"Company 1","state":1,"createdOn":"2016-11-12T21:10:41"}
,{"companyId":3,"name":"Mars","state":0,"createdOn":"2016-11-12T21:10:41"}
,{"companyId":4,"name":"Veronica","state":0,"createdOn":"2016-11-12T21:10:41"}]

Expected results:

{  
  "@odata.context":"some local url",
  "@odata.count": 9,  
  "value": [{"companyId":2,"name":"Company 1","state":1,"createdOn":"2016-11-12T21:10:41"}
    ,{"companyId":3,"name":"Mars","state":0,"createdOn":"2016-11-12T21:10:41"}
    ,{"companyId":4,"name":"Veronica","state":0,"createdOn":"2016-11-12T21:10:41"}]
} 

Solution

  • I did not inherit from the correct controller type, I should have been inheriting from ODataController and not ApiController.

    public sealed class CompanyController : ODataController
    

    Doing this solved that issue and odd side effects I was facing like properties not being ignored.