DEV Community

Cover image for A Detailed Tutorial on Pagination for ASP.NET Core Web APIs 🚀

Posted on

A Detailed Tutorial on Pagination for ASP.NET Core Web APIs 🚀

Pagination and Filtering implementation in an API is a common practice to optimize responses and efficiently handle large datasets. Here’s a step-by-step guide on how to achieve this in an ASP.NET Core Web API from beginners to intermediate developers.

Setting Up Your ASP.NET Core Web API Project

Step 1: Start creating a New ASP.NET Core Web API Project

First things first, we need to create our project. You can do this using Visual Studio or the command line interface. For the CLI, simply run:

dotnet new webapi -n PaginationSample

Enter fullscreen mode Exit fullscreen mode

Open the created folder and get coding!

Step 2: Define Your Model Class

Next, we’ll define a model class that will represent our data. For this example, let’s create a class named ListCSharpCornerArticles.

public class ListCSharpCornerArticles


    public int Id { get; set; }

    public string Title { get; set; }

    public string Category { get; set; }


Enter fullscreen mode Exit fullscreen mode

This class has three properties: Id, Title, and Category. Simple and straightforward!

Creating and Configuring Middleware

Step 3: Create Custom Middleware for Logging Incoming Requests

Middleware is like the bouncer at a club—it controls what happens with each request before it reaches the controller. Let’s create a custom logging middleware.

using Microsoft.AspNetCore.Builder;

using Microsoft.AspNetCore.Http;

using Microsoft.Extensions.Logging;

using System.Threading.Tasks;

public class RequestLoggingMiddleware


    private readonly RequestDelegate _next;

    private readonly ILogger<RequestLoggingMiddleware> _logger;

    public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)


        _next = next;

        _logger = logger;


    public async Task Invoke(HttpContext context)


        _logger.LogInformation($"Request: {context.Request.Method} {context.Request.Path}");

        await _next(context);



Enter fullscreen mode Exit fullscreen mode

This middleware logs the HTTP method and the request path. Handy for debugging, right?

Step 4: Configure the Custom Middleware

Now that we have the middleware, let’s configure our application to use it. This involves modifying the Startup.cs file.

using Microsoft.AspNetCore.Builder;

using Microsoft.AspNetCore.Hosting;

using Microsoft.Extensions.Configuration;

using Microsoft.Extensions.DependencyInjection;

using Microsoft.Extensions.Hosting;

public class Startup


    public IConfiguration Configuration { get; }

    public Startup(IConfiguration configuration)


        Configuration = configuration;


    public void ConfigureServices(IServiceCollection services)





    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)


        if (env.IsDevelopment())






        app.UseEndpoints(endpoints =>






Enter fullscreen mode Exit fullscreen mode

Now, every incoming request will be logged!

Implementing Pagination and Filtering in the Controller

Step 5: Create a Controller That Handles Pagination and Filtering

Finally, let’s put it all together in a controller.

using Microsoft.AspNetCore.Mvc;

using System;

using System.Collections.Generic;

using System.Linq;



public class CSharpCornerArticlesController : ControllerBase


    private static List<ListCSharpCornerArticles> _articles = GenerateSampleArticles();

    private static List<ListCSharpCornerArticles> GenerateSampleArticles()


        // Generate and return sample articles

        return new List<ListCSharpCornerArticles>


            new ListCSharpCornerArticles { Id = 1, Title = "Introduction to ASP.NET Core", Category = "ASP.NET Core" },

            new ListCSharpCornerArticles { Id = 2, Title = "Advanced C# Techniques", Category = "C#" },

            // Add more sample articles




    public IActionResult Get([FromQuery] int page = 1, [FromQuery] int pageSize = 10, [FromQuery] string filter = "")


        var query = _articles.AsQueryable();

        if (!string.IsNullOrEmpty(filter))


            query = query.Where(article => article.Title.Contains(filter) || article.Category.Contains(filter));


        var totalCount = query.Count();

        var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);

        query = query.Skip((page - 1) * pageSize).Take(pageSize);

        var result = new


            TotalCount = totalCount,

            TotalPages = totalPages,

            CurrentPage = page,

            PageSize = pageSize,

            Articles = query.ToList()


        return Ok(result);



Enter fullscreen mode Exit fullscreen mode

In this controller, we handle both pagination and filtering. The Get endpoint takes page, pageSize, and filter as query parameters, filters the articles accordingly, and returns a user-friendly paginated result.


By now, you’ve got a robust understanding of how to implement pagination and filtering in an ASP.NET Core Web API. Not only have you learned how to structure your data, but you’ve also picked up on creating custom middleware for better logging and debugging. Here’s a quick recap:

  • Pagination helps divide large datasets into manageable chunks.

  • Filtering lets users request specific subsets of data.

  • Combining both techniques enhances performance and usability.

Organize your API with pagination and filtering and make your life (and your users’ lives) easier!

Top comments (2)

kimfom01 profile image
Kim Fom • Edited

Will using yield return work for the same purpose?

bytehide profile image

Hi @kimfom01 thanks for your comment. Regarding to your question using yield return can certainly work for similar purposes, especially when handling large datasets. yield return allows you to stream data one item at a time, which can be particularly useful for scenarios where you want to improve memory efficiency and reduce the initial response times for large collections.

In the context of an ASP.NET Core Web API, you could leverage yield return to implement pagination more efficiently.

If you have any doubt, just let us know!