DEV Community

Cover image for Pagination in C#: Complete Guide with Easy Code Examples šŸ“š
ByteHide
ByteHide

Posted on

Pagination in C#: Complete Guide with Easy Code Examples šŸ“š

Introduction to Pagination in Csharp

Today, weā€™re diving into pagination in C#. Imagine showing a library with thousands of books ā€“ you wouldnā€™t want your users to scroll endlessly, right? This is where pagination saves the day! Weā€™ll explore what pagination is, why itā€™s important, and common scenarios where youā€™ll need it.

What is Pagination?

Pagination is a technique to split large data sets into smaller, manageable chunks or pages. Think of it like reading a book ā€“ instead of viewing the entire book at once, you read one page at a time.

Why Use Pagination in Web Applications?

Pagination helps improve user experience by loading only a subset of data at a time. It reduces load times, decreases server stress, and makes navigating data way easier for users.

Common Scenarios for Pagination

  • List of Products in an E-commerce Store

  • Search Results from a Database

  • Displaying Log Entries in an Admin Panel

Once we know what Pagination is, letā€™s jump into how you can implement pagination in your C# projects!

Implementing Pagination in Csharp

Letā€™s start with the set up of Pagination in C#. Weā€™ll discuss basics like the Skip and Take methods, using LINQ, ASP.NET Core, and more. Strap in!

Basic Pagination with Skip and Take

To paginate through data in C#, you can use the Skip and Take methods together. Hereā€™s a simple example:


var pageNumber = 1;

var pageSize = 10;

var paginatedData = dataArray

    .Skip((pageNumber - 1) * pageSize)

    .Take(pageSize)

    .ToList();

Enter fullscreen mode Exit fullscreen mode

In this snippet:

  • pageNumber: The number of the page you want to display.

  • pageSize: How many items to show per page.

  • Skip: Skips over a specified number of elements.

  • Take: Takes the specified number of elements after the skip.

Using LINQ for Efficient Pagination

LINQ (Language-Integrated Query) is a powerful tool in C#. Pagination with LINQ is easy and very readable:


var pageNumber = 2;

var pageSize = 5;

var pagedQuery = from item in dataArray

                 orderby item.SomeProperty

                 select item;

var paginatedResult = pagedQuery

    .Skip((pageNumber - 1) * pageSize)

    .Take(pageSize)

    .ToList();

Enter fullscreen mode Exit fullscreen mode

This example orders the items by SomeProperty before applying Skip and Take.

Pagination in ASP.NET Core

ASP.NET Core makes pagination even simpler. You can create a paginated response in your controller:


[HttpGet]

public IActionResult GetPagedData(int pageNumber = 1, int pageSize = 10)

{

    var data = _context.DataSet

        .Skip((pageNumber - 1) * pageSize)

        .Take(pageSize)

        .ToList();



    return Ok(data);

}

Enter fullscreen mode Exit fullscreen mode

And just like that, your API endpoint is ready to serve paginated data.

Handling Pagination with Entity Framework Core

Entity Framework Core (EF Core) supports pagination out of the box. Hereā€™s an example of paginating data with EF Core:


public async Task<IActionResult> GetPagedData(int pageNumber = 1, int pageSize = 10)

{

    var data = await _context.DataEntities

        .OrderBy(d => d.SomeProperty)

        .Skip((pageNumber - 1) * pageSize)

        .Take(pageSize)

        .ToListAsync();



    return Ok(data);

}

Enter fullscreen mode Exit fullscreen mode

Using ToListAsync ensures the paginated data retrieval is efficient and non-blocking.

Pagination for Large Data Sets

When dealing with large data sets, you need to be mindful of performance. Hereā€™s a quick tip: always index your database columns youā€™re sorting by. This can significantly speed up queries.

Advanced Pagination Techniques

Alright, letā€™s up our game and dive into some advanced stuff. Custom logic, server/client-side pagination, and even infinite scroll.

Custom Pagination Logic

Custom pagination might be needed for more control. For instance, if you want unique page numbering, sorting, or filtering:


public PagedResult<T> GetPagedData<T>(IQueryable<T> query, int page, int pageSize) where T : class

{

    var result = new PagedResult<T>

    {

        CurrentPage = page,

        PageSize = pageSize,

        RowCount = query.Count()

    };



    var pageCount = (double)result.RowCount / pageSize;

    result.PageCount = (int)Math.Ceiling(pageCount);



    var skip = (page - 1) * pageSize;

    result.Results = query.Skip(skip).Take(pageSize).ToList();



    return result;

}

Enter fullscreen mode Exit fullscreen mode

Here, PagedResult<T> is a helper class encapsulating paginated data and meta-information like CurrentPage, PageSize, RowCount, etc.

Server-Side vs. Client-Side Pagination

Letā€™s break it down:

  • Server-Side Pagination: Data is fetched page by page from the server. Suitable for huge datasets.

  • Client-Side Pagination: All data is loaded upfront, and pagination controls which part is visible. Good for small datasets to minimize server calls.

Performance Considerations for Pagination in Csharp

To make your pagination efficient:

  • Use database indexing.

  • Avoid fetching unnecessary data.

  • Implement caching if data doesnā€™t change frequently.

Infinite Scroll Pagination

Ever been on Instagram or Twitter? Thatā€™s infinite scroll pagination. Hereā€™s how you could do it in C#:


public async Task<IActionResult> GetInfiniteScrollData(int lastItemId, int pageSize = 10)

{

    var data = await _context.DataEntities

        .Where(d => d.Id > lastItemId)

        .OrderBy(d => d.Id)

        .Take(pageSize)

        .ToListAsync();



    return Ok(data);

}

Enter fullscreen mode Exit fullscreen mode

In this example, lastItemId represents the ID of the last loaded item. Sweet, right?

Pagination in API Design

Designing APIs that support pagination can significantly enhance your applicationā€™s performance and usability. Stick around, weā€™re about to explore how to do this seamlessly.

Designing Paginated API Endpoints

When designing APIs, you can include parameters like page and size to handle pagination:


GET /api/data?page=1&size=10

Enter fullscreen mode Exit fullscreen mode

Implementing Pagination in ASP.NET Web API

Hereā€™s a practical implementation in ASP.NET Web API:


[HttpGet]

public async Task<IActionResult> GetPagedData(int pageNumber = 1, int pageSize = 10)

{

    var data = await _context.DataEntities

        .OrderBy(d => d.SomeProperty)

        .Skip((pageNumber - 1) * pageSize)

        .Take(pageSize)

        .ToListAsync();



    var totalRecords = await _context.DataEntities.CountAsync();

    var pagedData = new {

        TotalRecords = totalRecords,

        Data = data

    };



    return Ok(pagedData);

}

Enter fullscreen mode Exit fullscreen mode

This response includes both paginated data and the total record count, ensuring the client knows how many pages there are.

Working with Page Sizes and Limits in APIs

Itā€™s a good idea to include logic to handle page size limits, preventing requests for excessively large pages:


int MaxPageSize = 50;

pageSize = (pageSize > MaxPageSize) ? MaxPageSize : pageSize;

Enter fullscreen mode Exit fullscreen mode

User Interface and UX Considerations

Pagination isnā€™t just about the backend. It plays a huge role in the front-end UX. Letā€™s talk about making pagination user-friendly and seamless!

Designing User-Friendly Pagination Controls

Here are some tips:

  • Use understandable navigation controls like ā€œFirstā€, ā€œPreviousā€, ā€œNextā€, and ā€œLastā€.

  • Display current page and total page numbers.

  • Offer page size options (e.g., 10, 20, 50 items per page).

Adding Pagination to Razor Pages

In Razor Pages, adding pagination is straightforward. Hereā€™s an example of a paginated view:


@page

@model PagedListModel



<table>

    <thead>

        <tr>

            <th>Item</th>

        </tr>

    </thead>

    <tbody>

        @foreach (var item in Model.Items)

        {

            <tr>

                <td>@item.Name</td>

            </tr>

        }

    </tbody>

</table>



<nav aria-label="Page navigation">

    <ul class="pagination">

        <li class="page-item">

            <a class="page-link" href="?page=@(Model.CurrentPage - 1)">Previous</a>

        </li>

        @for (int i = 1; i <= Model.TotalPages; i++)

        {

            <li class="page-item">

                <a class="page-link" href="?page=@i">@i</a>

            </li>

        }

        <li class="page-item">

            <a class="page-link" href="?page=@(Model.CurrentPage + 1)">Next</a>

        </li>

    </ul>

</nav>

Enter fullscreen mode Exit fullscreen mode

Integrating Pagination with JavaScript and AJAX

Using JavaScript and AJAX, you can make page transitions smoother:


$(document).on('click', '.page-link', function(e) {

    e.preventDefault();

    var page = $(this).attr('href').split('page=')[1];



    $.ajax({

        url: '/api/data?page=' + page,

        type: 'GET',

        success: function(data) {

            // Update the table with new data

        }

    });

});

Enter fullscreen mode Exit fullscreen mode

This snippet hooks onto the pagination links, captures the click event, and fetches new data using AJAX.

Testing and Debugging Pagination

Even the best code can run into issues. Letā€™s make sure our pagination logic is robust and well-tested.

Unit Testing Pagination Logic

Unit tests ensure your pagination logic performs as expected:


[TestMethod]

public void TestPagination()

{

    var data = Enumerable.Range(1, 100).ToList();

    var pagedData = Paginate(data, 2, 10);



    Assert.AreEqual(10, pagedData.Count());

    Assert.AreEqual(11, pagedData.First());

    Assert.AreEqual(20, pagedData.Last());

}

Enter fullscreen mode Exit fullscreen mode

Common Issues and Troubleshooting

Common pagination issues include:

  • Incorrect page number calculations.

  • Off-by-one errors.

  • Performance bottlenecks with large datasets.

Performance Testing Pagination

Use tools like JMeter or Postman for performance testing your paginated endpoints. Ensure they handle concurrent users efficiently.

Best Practices and Tips for Effective Pagination

Letā€™s wrap up with some essential best practices and tips to make your pagination top-notch.

SEO Considerations for Paginated Content

Ensure each paginated page is crawlable by search engines:

  • Use rel="next" and rel="prev" links in the HTML <head>.

  • Include canonical tags to avoid duplicate content issues.

Efficient Database Queries for Pagination

Using indexed queries and TOP for efficient data retrieval:


var result = context.DataEntities

    .OrderBy(d => d.SomeProperty)

    .Skip((pageNumber - 1) * pageSize)

    .Take(pageSize)

    .ToList();

Enter fullscreen mode Exit fullscreen mode

Using Caching and Indexing for Improved Performance

Caching repeated queries and indexing frequently searched columns can drastically improve performance:

  • Utilize MemoryCache or Redis for caching.

  • Index database columns used in OrderBy, Where, and Join clauses.

Conclusion

Weā€™ve covered the basics of pagination, explored advanced techniques, and discussed API design and UX considerations. By now, you should be well-equipped to implement, optimize, and troubleshoot pagination in your C# applications.

Remember, effective pagination not only enhances performance but also greatly improves user experience. Happy coding!

Top comments (0)