Using SkipToken for Paging in Asp.Net OData and Asp.Net Core OData



Loading large data can be slow. Services often rely on pagination to load the data incrementally to improve the response times and the user experience. Paging can be server-driven or client-driven:

Client-driven paging

In client-driven paging, the client decides how many records it wants to load and asks the server for that many records. That is achieved by using $skip and $top query options in conjunction. For instance, if a client needs to request 10 records from 71-80, it can send a similar request as below:

However, this is problematic if the data is susceptible to change. In case of a deletion in between two requests for consecutive pages, a record will be served in both the requests.

Server-driven paging

In server-driven paging, the client asks for a collection of entities and the server sends back partial results as well as a nextlink to use to retrieve more results. The nextlink is an opaque link which may use $skiptoken to store state about the request, such as the last read entity.

Default NextLink Generation

Skiptoken is now available with Asp.NetCore OData >= 7.2.0 and Asp.Net OData >= 7.2.0. It can be enabled by calling SkipToken() extension method on HttpConfiguration.

The default implementation of the skiptoken handling is encapsulated by a new class – DefaultSkipTokenHandler. This class implements the abstract methods of the base class SkipTokenHandler, which basically determines the format of the skiptoken value and how that value gets used while applying the SkipTokenQueryOption to the IQueryable.

Format of the nextlink

The nextlink may contain $skiptoken if the result needs to be paginated. In the default implementation, $skiptoken value will be a list of pairs, where the pair consists of a property name and property value separated by a delimiter(:). The orderby property and value pairs will be followed by key property and value pairs in the value for $skiptoken. Each property and value pair will be comma separated.

Applying SkipToken Query Option

The skiptoken value is parsed into a dictionary of property name and property-value pairs.  For each pair, we compose a predicate on top of the IQueryable to ensure that the resources returned have greater (or lesser in case of desc orderby) values than the last object encoded in the nextlink.

Custom NextLink Generation

The library provides you with a way to specify your own custom nextlink generation through dependency injection. The code below is delegating the responsibility of handling nextlink to a new class named SkipTopNextLinkGenerator by calling into the container builder extension method in MapODataServiceRoute.

Generating the NextLink

A nextlink can be generated by implementing the GenerateNextPageLink method in a derived class of SkipTokenHandler. The instance passed to this method will be the last object being serialized in the collection.

However, if your paging strategy does not align with this approach for all your use cases. You can set the nextlink in your controller method by returning a paged result. This will override the nextlink that is generated by your implementation of the SkipTokenHandler.


Applying the SkipToken

In your custom nextlink generation, you are free to use the skiptoken in the nextlink to encode additional information that you may require. However, you will also have to implement how to use the SkipToken query option by implementing your own ApplyTo methods.

To implement your own ApplyTo, it may be useful to look at the DefaultSkipTokenHandler’s implementation.


Comments are closed.