Reputation: 6769
I'm using OData with ASP.NET Web API because I want to take advantage of its $skip option by using it for paging on the client. However, I face an issue and I'm not sure whether it is a bug or I'm doing something wrong.
I have the following method:
[HttpGet]
[Route("api/people")]
[EnableQuery(PageSize = 10, AllowedQueryOptions = AllowedQueryOptions.Skip)]
public IHttpActionResult GetAll()
{
// Declare a simple list of Person objects.
// Every Person object has only 3 properties - Id, Name and DateCreated.
var peopleList = new List<Person>();
for (int i = 0; i < 50; i++)
{
// Create the list with example Person objects.
// Start from new Person() { Id = 1, Name = "Person #1", DateCreated = Tomorrow.
// Continue with Person() { Id = 2, Name = "Person #2", DateCreated = The Day After Tomorrow.
// Do this till i == 50.
peopleList.Add(new Person()
{
Id = (i + 1),
Name = "Person #" + (i + 1),
DateCreated = DateTime.Now.AddDays(i)
});
}
// Get only those Person objects the Ids of which are prime numbers.
// Order the list by the most recently added, meaning the one that has a most recent DateCreated value.
var outputList = peopleList
.Where(p => p.Id % 2 == 0)
.OrderByDescending(p => p.DateCreated)
.ToList();
// Return the list from the method.
return Ok(outputList);
}
So, written this way I expect that if I make a request to "api/people", I will get the 10 most recent (because of the PageSize = 10 option written in the EnableQuery attribute) People objects with prime Ids. However, the result that I get is:
[
{
"id": 2,
"name": "Person #2",
"dateCreated": "2015-11-06T10:48:09.1224206+02:00"
},
{
"id": 4,
"name": "Person #4",
"dateCreated": "2015-11-08T10:48:09.1224206+02:00"
},
...
{
"id": 20,
"name": "Person #20",
"dateCreated": "2015-11-24T10:48:09.1224206+02:00"
}
]
If I exclude this line
[EnableQuery(PageSize = 10, AllowedQueryOptions = AllowedQueryOptions.Skip)]
I get the correct ordering but of course I'm getting the whole set of 50 Person objects, not just 10 as I want.
[
{
"id": 50,
"name": "Person #50",
"dateCreated": "2015-12-24T10:56:55.7456064+02:00"
},
{
"id": 48,
"name": "Person #48",
"dateCreated": "2015-12-22T10:56:55.7456064+02:00"
},
...
{
"id": 2,
"name": "Person #2",
"dateCreated": "2015-11-06T10:48:09.1224206+02:00"
}
]
I don't want to let the client order the list, the only thing that I want is to ensure that the maximum size of the returned collection is 10 objects and that the client can specify the number of objects to be skipped (using the $skip option).
So, why is this thing happening like that and how can I fix it?
Upvotes: 2
Views: 1204
Reputation: 6769
Okay, I found the solution here. It seems like I have to add EnableStableOrdering = false to my EnableQuery attribute like this:
Solution:
[EnableQuery(PageSize = 10, AllowedQueryOptions = AllowedQueryOptions.Skip, EnsureStableOrdering = false)]
Here's what EnableStableOrdering really does (got from source code):
Summary:
Gets or sets a value indicating whether query composition should alter the original query when necessary to ensure a stable sort order.
Returns:
A true value indicates the original query should be modified when necessary to guarantee a stable sort order. A false value indicates the sort order can be considered stable without modifying the query. Query providers that ensure a stable sort order should set this value to false. The default value is true.
As the default value of this option is true, I just had to set it to false.
Upvotes: 1