Introduction

This blog is the second part in a series of blogs that will cover CosmosDB pagination. If you want to know more about page number and page size pagination or the prerequisites for what we are doing please take a look at the previous blog covering the premise and the installation here.

In this 2-part blog series we will go in detail on how you can implement different types of server side pagination with Cosmos DB in your application.

The pagination types that I will cover in these 2 blogs are the following:

I will be implementing these solutions in a single Blazor project with one page per pagination type.

This blog is the second part of these series. It will cover the "Next" and "Previous" type of pagination.

You can read the first part of the series about page number and page size pagination here .

Next/Previous pagination

Even though it's not as popular as page number and page size, this form of pagination is the fastest and the most cost efficient type of pagination that Cosmos DB currently supports.

For this form of pagination all we need is 2 properties.

  • Page size
  • Request continuation token

"But what is the continuation token?", I hear you asking.

Cosmos DB only supports queries though a form of paged results. What this means is that if you query a bunch of documents that match some criteria, it is almost certain that these documents don't come back in a single round trip to CosmosDB but in several. The reason why Cosmos DB operates that way is probably a reason for a blog post all together so I won't dive deeper into it here.

What you need to know is that, in order to make this pagination querying really efficient, Cosmos DB will keep some state between round trips in order to inform the server that this query is the next one after a previous request.

An example of a request continuation token is the following:

[{"compositeToken":{"token":null,"range":{"min":"","max":"05C1C9CD673398"}},"orderByItems":[{"item":"Test 5"}],"rid":"Okp7AOBkXXAUAAAAAAAAAA==","skipCount":0,"filter":null}]

You don't need to know what each of these properties mean. It's completely abstracted to you. All you need to know is that if you do some sort of query and it has a request continuation token in the response headers then there are more results that match your querying expression.

The reason why I'm telling you all this, is because the only type of state you need to keep on the client side in order to implement Next/Previous button pagination is the continuation token.

Let's look at the code.

Just like in the previous blog, we need a pager class that will keep everything we need to know about the pagination status of our request. In this case it will be way simpler. We only need the continuation token and a boolean that indicates whether our request has more pages after the current one.

Also, just like in the previous blog, we need a data class that keeps a combination of entity results and the current pager status. This class looks like this.

The backend code

Now that we have all that set-up let's see how our endpoint will be looking like.

First, we will need to register our Student CosmosStore on our Server's Startup.cs file inside the ConfigureServices method.

Adding those lines allows us to get ICosmosStore<Student> from .NET Core's dependency injection as shown below.

All our endpoints need to do is to get two query string parameters in order to return data relevant to the paged request. Those parameters are the continuation token and the page size.

Here's the final version of the endpoint.

ToPagedListAsync is a Cosmonaut extension method that will run a Query that is using pagination and it will return not only the entities we queried for but also whether there are more pages for this query and also the continuation token itself. This token will be returned to the client and from there we will use it in our next request.

The frontend code

First we need to add our functions code in our .cshtml file.

Let's see what's going on in this snippet.

First you need to know that if you use an empty or null continuation token in Cosmonaut, it will always return the first page of the results. That's why we send string.Empty on initial page load.

In order to make our page to support both Next and Previous buttons we need to keep history of the continuation token that we used per page. For that reason I will use a dictionary that has a key representing the page number and value representing the continuation token.

Something else that's really important is that, because the continuation token has some characters that don't play nice in the url, we will need to UrlEncode it. We can use .NET Standard's WebUtility.UrlEncode(continuationToken) method for that.

Visualising the results with Blazor is as simple as doing the following:

Now every time our _students field changes in any way, the changes will be automatically reflected in our frontend.

The pagination part of the page is way less complicated than the page number and page size one. We only have 3 buttons. First, Next and Previous.

Here's a gif demonstrating the functionality that we just implemented.

Keep in mind this is 100% server side pagination. There are no results being cached on the client side.

Observations

This form of pagination is one that Cosmos DB fully supports at the moment. It is the fastest and most efficient way to do pagination and that's the recommended approach. In a future blog post we will be looking at other examples where we can combine this, with page number and caching to give a better user experience.

You can read more about pagination recommendations here.

You can find a live version of the pagination app here: https://cosmosdbpage.azurewebsites.net

You can find the complete solution for this blog post here: https://github.com/Elfocrash/CosmosDBPaginationSample