Search code examples
asp.netasp.net-web-apiodata

OData paging with expand issue


I'm using OData v5/Web API 2.2 to create an endpoint that will return a list of employees from each company.

My problem occurs when I try to implement server-side paging while also using the OData $expand property. When I try to make a call to

http://localhost:60067/Companies?$expand=Employees

I get an error that says "Could not find a property named 'Employees' on type 'System.Web.OData.Query.Expressions.SelectAllAndExpand_1OfCompanyApiModel'"

However, when I removed the EnableQuery attribute the call to the endpoint or when I didn't expand it works as expected. Does anyone have an idea of what I am doing wrong? I've been googling this for a while but haven't found anything.

Here are some code snippets -

Data Models:

public class CompanyApiModel
{
    [Key]
    public Guid CompanyGuid { get; set; }
    [Required]
    public string Name { get; set; }
    // other properties
    public List<EmployeeApiModel> Employees { get; set; }
}

public class EmployeeApiModel
{
    [Key]
    public Guid EmployeeGuid { get; set; }
    [Required]
    public string Name { get; set; }
    // other properties
}

CompaniesController.cs:

[EnableQuery(PageSize = 10)] // If I comment this out everything works
//[EnableQuery] // This fails as well
public IHttpActionResult Get(ODataQueryOptions<CompanyApiModel> queryOptions)
{
    var companies = GetCompanies(queryOptions);
    return Ok(companies);
    // return Ok(companies.AsQueryable()); // This doesn't work either
}

WebApiConfig.cs:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;  

        var routingConventions = ODataRoutingConventions.CreateDefault();
        routingConventions.Insert(0, new OptionsRoutingConvention());
        config.MapODataServiceRoute("odata", null, GetEdmModel(), new DefaultODataPathHandler(), routingConventions);


        // below code allows endpoints to respond with either XML or JSON, depending on accept header preferences sent from client 
        // (default in absence of accept header is JSON)
        var odataFormatters = ODataMediaTypeFormatters.Create();
        config.Formatters.InsertRange(0, odataFormatters);

        config.EnsureInitialized();

    }

    public static IEdmModel GetEdmModel()
    {
        ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
        builder.Namespace = "Demos";
        builder.ContainerName = "DefaultContainer";

        builder.EntitySet<CompanyApiModel>("Companies");
        builder.EntitySet<EmployeeApiModel>("Employees");

        var edmModel = builder.GetEdmModel();
        return edmModel;
    }
}

Solution

  • Figured out the problem. We were overriding the EnableQuery attribute somewhere in our code and calling it EnableMappedQuery and applying it to the controller. Thus instead of having [EnableQuery(PageSize = 10)] I should have had [EnableMappedQuery(PageSize = 10)].