Pagination in .Net Api
Tags: dotnet, programming, tutorial
Published: 2024-02-02 07:41:13

### Pagination in ASP.NET Core Web API with Entity Framework Core 
Pagination is a technique to divide a large list of items into multiple pages. It is used to improve the performance of the application by reducing the amount of data sent to the client. In this article, we will learn how to implement pagination in an ASP.NET Core Web API application with Entity Framework Core and SQL Server.

 We will use the repository pattern to access the database. We will use the Newtonsoft.Json library to ignore reference loops in the JSON response.


#### Prerequisites
* .NET 
* Visual Studio or any code editor
* SQL Server
* Postman or any API testing tool

#### Create a new .NET Web API application
```bash
dotnet new webapi  --use-controllers 
```


#### Install packages
```bash
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson
```

### create a Player model
```csharp
public class Player
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Club { get; set; }
    public DateTime Created { get; set; }
}
```

#### Create the PaginatedList class in the Models folder
```csharp
public class PaginatedList<T>
{
    public List<T> Items { get; }
    public int PageIndex { get; }
    public int TotalPages { get; }
    public bool HasPreviousPage => PageIndex > 1;
    public bool HasNextPage => PageIndex < TotalPages;

    public PaginatedList(List<T> items, int pageIndex, int totalPages)
    {
        Items = items;
        PageIndex = pageIndex;
        TotalPages = totalPages;
    }
}
```


#### Create the ApiResponse class in the Models folder
```csharp
public class ApiResponse
{
    public bool Success { get; set; }
    public string Message { get; set; } = null;
    public object Data { get; set; }

    public ApiResponse(bool success, string message, object data)
    {
        Success = success;
        Message = message;
        Data = data;
    }
}
```


#### AppDbContext class in the Data folder
```csharp
public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {
    }

    public DbSet<Player> Players { get; set; }
}
```


#### IPlayerRepository
```csharp
public interface IPlayerRepository
{
    Task<PaginatedList<Player>> GetPlayers(int pageIndex, int pageSize);
    Task<Player> AddPlayer(Player player);
}
```

#### PlayerRepository
```csharp
public class PlayerRepository : IPlayerRepository
{
    private readonly AppDbContext _context;

    public PlayerRepository(AppDbContext context)
    {
        _context = context;
    }

    public async Task<PaginatedList<Player>> GetPlayers(int pageIndex, int pageSize)
    {
        var players = await _context.Players
            .OrderBy(b => b.Id)
            .Skip((pageIndex - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();

        var count = await _context.Players.CountAsync();
        var totalPages = (int)Math.Ceiling(count / (double)pageSize);

        return new PaginatedList<Player>(players, pageIndex, totalPages);
    }

    public async Task<Player> AddPlayer(Player player)
    {
        _context.Players.Add(player);
        await _context.SaveChangesAsync();
        return player;
    }
}
```

#### PlayerController class
```csharp
[ApiController]
[Route("api/[controller]")]
public class PlayerController : ControllerBase
{
    private readonly IPlayerRepository _playerRepository;

    public PlayerController(IPlayerRepository playerRepository)
    {
        _playerRepository = playerRepository;
    }

    [HttpGet]
    public async Task<ActionResult<ApiResponse>> GetPlayers(int pageIndex = 1, int pageSize = 10)
    {
        var players = await _playerRepository.GetPlayers(pageIndex, pageSize);
        return new ApiResponse(true, null, players);
    }

    [HttpPost]
    public async Task<ActionResult<ApiResponse>> AddPlayer(Player player)
    {
        var newPlayer = await _playerRepository.AddPlayer(player);
        return new ApiResponse(true, null, newPlayer);
    }
}
```


#### Program.cs
```csharp
using Microsoft.EntityFrameworkCore;
using pagina.Data;
using pagina.Repository;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddDbContext<AppDbContext>(options =>
   {
       options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
   });

builder.Services.AddControllers().AddNewtonsoftJson(options =>
{
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});

builder.Services.AddScoped<IPlayerRepository, PlayerRepository>();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

```

#### appsettings.json
```json
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=myapp;User Id=sa;Password=********(!)Password;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}
```


#### Migrations
```bash
dotnet ef migrations add InitialCreate
dotnet ef database update
```

#### Run the application
```bash
dotnet run
```