Introduction
OData (Open Data Protocol) is an open protocol for sharing the data. There is built-in support of OData in Web API. OData URI is also support the filter expression.
One of the common requirements for web application is displaying partial data from a large result set. For example user may able to browse the 50 records from 1 lakh of records and the next 50 records will be populated when the user is in the next page. If we display all records in single page, it would affect performance significantly.
We can implement Paging in two ways. Web API has built-in support for both option client and server driven paging.
Client Driven Paging
The client decides how many records contained by the page and tell it to server for page of size.
Server Driven Paging
Here client is just sending requests for the collection of entities and server returns partial results like which is used to retrieve more results
Client - Driven Paging
As we know, we can define the parameters with OData URI to modify the OData query. Client sends these parameters in the query string of URI. Client driven paging can be implemented with the OData query.
OData Query Options
Following OData query options supported by Web API.
Options |
Description |
$orderby |
Used for sorting |
$select |
Select which properties are included in result set |
$skip |
How many record wants to skip |
$top |
How many record wants to retrieve |
$filter |
Filter the result set |
$expand |
Expand the related entity |
$inlinecount |
Used to include total record count in response |
As query option has keyword $top and $skip. $top is used tell server how many records client wants. We can turn on the client query support with "Queryable" or "EnableQuery" attribute defined on top of action method of Web API.
Example
I have taken same example which was used in my previous article. In this example I have created in-memory data source and configured the end point. In data source, I have added some more entries.
-
-
-
-
- public List<TestData> CreateTestData()
- {
- List<TestData> data = new List<TestData>();
- data.Add(new TestData { Id = 1, Name = "Jignesh", Role = "Project Manager" });
- data.Add(new TestData { Id = 2, Name = "Tejas", Role = "Architect" });
- data.Add(new TestData { Id = 3, Name = "Rakesh", Role = "Lead" });
- data.Add(new TestData { Id = 4, Name = "Hiren", Role = "Developer" });
- data.Add(new TestData { Id = 5, Name = "Pooja", Role = "Developer" });
- data.Add(new TestData { Id = 6, Name = "Keyur", Role = "Developer" });
- data.Add(new TestData { Id = 7, Name = "Ashish", Role = "Developer" });
- data.Add(new TestData { Id = 8, Name = "Parth", Role = "Developer" });
- data.Add(new TestData { Id = 9, Name = "Manish", Role = "QA" });
- data.Add(new TestData { Id = 10, Name = "Manisha", Role = "QA" });
- data.Add(new TestData { Id = 11, Name = "Urmi", Role = "QA" });
- data.Add(new TestData { Id = 12, Name = "Bharat", Role = "QA" });
- data.Add(new TestData { Id = 13, Name = "Varun", Role = "QA" });
- data.Add(new TestData { Id = 14, Name = "Komal", Role = "QA" });
- data.Add(new TestData { Id = 15, Name = "Dhaval", Role = "QA" });
- data.Add(new TestData { Id = 16, Name = "Chirag", Role = "Project Manager" });
- data.Add(new TestData { Id = 17, Name = "Devid", Role = "QA" });
- data.Add(new TestData { Id = 18, Name = "Vivek", Role = "Developer" });
- data.Add(new TestData { Id = 19, Name = "Purvi", Role = "Architect" });
- data.Add(new TestData { Id = 20, Name = "Denish", Role = "Developer" });
-
- return data;
- }
I have tried following URI, it returns top five records.
URI: http://localhost:24367/TestData?$top=5
Output :
- {
- "@odata.context":"http://localhost:24367/$metadata#TestData","value":[
- { "Id":1,"Name":"Jignesh","Role":"Project Manager" },
- { "Id":2,"Name":"Tejas","Role":"Architect" },
- { "Id":3,"Name":"Rakesh","Role":"Lead" },
- { "Id":4,"Name":"Hiren","Role":"Developer" },
- { "Id":5,"Name":"Pooja","Role":"Developer" }
- ]
- }
If we want the next 5 records, we can use $skip query option to ignore the first five records. So I have tried following URI now.
URI: http://localhost:24367/TestData?$skip=5&$top=5
Output:
- {
- "@odata.context":"http://localhost:24367/$metadata#TestData","value":[
- { "Id":6,"Name":"Keyur","Role":"Developer" },
- { "Id":7,"Name":"Ashish","Role":"Developer" },
- { "Id":8,"Name":"Parth","Role":"Developer" },
- { "Id":9,"Name":"Manish","Role":"QA" },
- { "Id":10,"Name":"Manisha","Role":"QA" }
- ]
- }
We can also use $filter query option with above URI to narrowing the records.
URI: http://localhost:24367/TestData?$filter=Role eq 'QA'&$skip=5&$top=5
Output:
- {
- "@odata.context":"http://localhost:24367/$metadata#TestData","value":[
- { "Id":14,"Name":"Komal","Role":"QA" },
- { "Id":15,"Name":"Dhaval","Role":"QA" },
- { "Id":17,"Name":"Devid","Role":"QA" }
- ]
- }
Server driven Paging
In client driven paging, client always sends a number that indicates how many records are wanted. This number is sent to the server by using $top query option. In Server driven paging, server has control on page size. We are able to pass page size to EnableQuery or Queryable attribute. When we do the server driven paging, server always returns next page link to the response body.
So now Web API method is rewritten to:
- [EnableQuery(PageSize=5)]
- public IHttpActionResult Get()
- {
- var result = CreateTestData().AsQueryable();
- return Ok(result);
- }
URL: http://localhost:24367/TestData?$filter=Role eq 'QA'
Output
- {
- "@odata.context":"http://localhost:24367/$metadata#TestData","value":[
- { "Id":9,"Name":"Manish","Role":"QA" },
-
- { "Id":10,"Name":"Manisha","Role":"QA" },
- { "Id":11,"Name":"Urmi","Role":"QA" },
- { "Id":12,"Name":"Bharat","Role":"QA" },
- {"Id":13,"Name":"Varun","Role":"QA" }
- ],"@odata.nextLink":"http://localhost:24367/TestData?$filter=Role%20eq%20%27QA%27&$skip=5"
- }
As we have seen in above example, server will return data along with next URI. Next link is generated based on $skip.
$inlinecount query option
In server driven paging, client has easy navigation to the next page by using next link and in the same way client can navigate to previous page by remembering URI associated with current page while navigate to next page.
$inlinecount query option can be applied to any query to get total number of records. If we have total records and page size than we can easy create next and previous URI.
Currently, $inlinecount query option is supported by OData but not supported by Web API. In feature release, it can be added.
Summary
We can implement Paging in two ways in Web API using OData.
- Client driven paging
- Server driven paging
Hope this will help you.
Read more articles on ASP.NET: