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?
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.