Can I change the ODataQueryOptions used for my ODataController's request?

Jodrell picture Jodrell · May 7, 2014 · Viewed 8.1k times · Source

Update

vote here on User Voice to get the ambiguity addressed.


I've written a OData WebAPI controller inherting from ODataController.

public class ManyColumnsController : ODataController
{
    [Queryable(
        AllowedOrderByProperties = "Aa,Bb,Cc,Dd",
        EnsureStableOrdering = false,
        MaxOrderByNodeCount = 2)]
    public IQueryable<ManyColumn> GetManyColumns(
            ODataQueryOptions<ManyColumn> options)
    {
        // Because I've disabled EnsureStableOrdering,
        // I need to check column "Dd" is always included
        // in the OrderBy option. This will ensure stable ordering.
        if (!options.OrderBy.RawValue.Contains("Dd")
        {
             var entityType = options.Context.ElementType as IEdmEntityType;
             var ddProperty = entityType.DeclaredStructuralProperties()
                 .Single(p => p.Name == "Dd");
             options.OrderBy.OrderByNodes.Add(new OrderByPropertyNode(
                 ddProperty,
                 OrderByDirection.Descending));
        }

        return this.context.ManyColumns;
    }
}

This code runs and an extra OrderByNode is added to the OrderBy property of the ODataQueryOptions passed into the method.

The Problem

This alteration has no effect on the statement that is generated by the contoller. Processing continues as if I had changed nothing and any OrderBy applied to the ManyColumns entity is replaced with the orignal OrderBy specified in the $orderby parameter of the original request.

On further examination it seems that ODataQueryOptions is probably intended to be immutable. Most of its properties have only get accessors.

The Question

Have I just misused a failing in the implementation of OrderByQueryOption?

Is there a way to amend the ODataQueryOptions that will be applied to the request, later in the pipeline?

Answer

Colby Cavin picture Colby Cavin · May 15, 2014

You should remove the [Queryable] attribute.

According to http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options#ODataQueryOptions, you should use either Queryable or manually manipulate the ODataQueryOptions. The web API populates the ODataQueryOptions from the URI query string, after which you could (presumably) alter those options.

Further down the page, they implement something that looks really close to a solution for your problem. They implement a custom MyQueryable attribute which enforces a custom order-by validator. You may not be able to alter the query during validation, but you may be able to override the attribute's implementation of ApplyQuery to inject your required order-by clause.