Pagination using ASP.NET Core 2.1

min read

Phân trang (pagination) trong ASP.NET Core 2.1, Trong bài viết này mình viết một đoạn code phân trang bằng code thuần, không sử dụng Plugin, để giúp mọi người dễ hình dung ra hơn
Trong các bài viết ASP.NET MVC 5, vừa qua có bài viết về phân trang bạn có thể xem lại tại đây:

+ Pagination For Search Results ASP.NET MVC 5
+ ASP.NET MVC 5 Ajax Pagination For Search Results

# Create Project ASP.NET Core 2.1

Bước 1: Trong Visual Studio 2019, Bạn chọn File->New, chọn Project
Bước 2: Chọn Create a new project
Bước 3: Chọn ASP.NET Core Web Application template
Bước 4: Đặt tên Project, chọn Create. 
Bước 5: Select .NET Core, ASP.NET Core 2.1, Chọn Web Application (Model-View-Controller), sau đó bấm Create

# Cài đặt EntityframeworkCore

Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools

# Cấu hình Models

Tạo class Product.cs trong thư mục Models
+ Models/Product.cs

public class Product
    {
        public int idProduct { get; set; }
        public string Title { get; set; }
        public string UrlImage { get; set; }
        public string Detail { get; set; }
        public int Price { get; set; }


    }

Tạo chuổi Connectstring để kết nối SQL SERVER, mở appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "EFDataContext": "Server=DESKTOP-GCABV8F\\SQLExpress;Database=DB_Pagination;Trusted_Connection=True;MultipleActiveResultSets=true"
  }

}

Tạo class EFDataContext.cs trong thư mục Models, để connect truy xuất, thao tác cơ sở dữ liệu
+ Models/EFDataContext.cs

using Microsoft.EntityFrameworkCore;
namespace PaginationASPCore.Models
{
    public class EFDataContextcs : DbContext
    {
        public EFDataContextcs(DbContextOptions<EFDataContextcs> options): base(options) { }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Product>().HasKey(s => s.idProduct);
        }
        public DbSet<Product> Products { get; set; }
    }
}

Đăng ký dịch vụ service EFDataContext trong Startup.cs

services.AddDbContext<EFDataContextcs>(options=>options.UseSqlServer(Configuration.GetConnectionString("EFDataContext"),
                builder => builder.UseRowNumberForPaging()));

# Chạy Migration in ASP.NET Core 2.1

add-migration dbpagination
update-database

# Tạo thư mục Services

Sao đó tạo file IProduct.cs cấu hình các phương thức sau
+ Services/IProduct.cs

using PaginationASPCore.Models;
namespace PaginationASPCore.Services
{
    public interface IProduct
    {
        IEnumerable<Product> getProductAll();
        int totalProduct();
        int numberPage(int totalProduct, int limit);
        IEnumerable<Product> paginationProduct(int start, int limit);


    }
}

+ getProductAll(): lấy danh sách dữ liệu product
+ totalProduct(): trả vể tổng số product
+ numberPage(): trả về số number page cần hiển thị
+ paginationProduct(): lấy danh sách theo limit

+ Services/ItemProductService.cs : kế thừa từ file IProduct.cs, để cấu hình các phương thức bên trong nó

using PaginationASPCore.Models;
namespace PaginationASPCore.Services
{
    public class ItemProductService : IProduct
    {
        private readonly EFDataContextcs _db;
        private List<Product> products  = new List<Product>();
        public ItemProductService(EFDataContextcs db)
        {
            _db = db;
            this.products = _db.Products.ToList();
        }
        public IEnumerable<Product> getProductAll()
        {
            return products;
        }
        public int totalProduct()
        {
            return products.Count; 
        }
        public int numberPage(int totalProduct,int limit)
        {
            float numberpage = totalProduct / limit;
            return (int)Math.Ceiling(numberpage);
        }
        public IEnumerable<Product> paginationProduct(int start, int limit)
        {
            var data = (from s in _db.Products select s);
            var dataProduct = data.OrderByDescending(x => x.idProduct).Skip(start).Take(limit);
            return dataProduct.ToList();
        }
    }
}

Đăng ký service IProduct.cs & ItemProductService.cs trong file Startup.cs

services.AddScoped<IProduct, ItemProductService>();

Bạn có thể tìm hiểu thêm về bài viết: Add Service in ASP.NET Core 2.1

# Cấu hình Controller

Tạo file ProductController.cs trong thư mục Controllers
+ Controllers/ProductController.cs

using Microsoft.AspNetCore.Mvc;
using PaginationASPCore.Services;
namespace PaginationASPCore.Controllers
{
    public class ProductController : Controller
    {
        private readonly IProduct _product;
        public ProductController(IProduct product)
        {
            _product = product;
        }
        public IActionResult Index(int? page=0)
        {
            int limit = 2;
            int start;
            if (page > 0)
            {
                page = page;
            }
            else
            {
                page = 1;
            }
            start = (int)(page - 1) * limit;

            ViewBag.pageCurrent = page;

            int totalProduct = _product.totalProduct();

            ViewBag.totalProduct = totalProduct;

            ViewBag.numberPage = _product.numberPage(totalProduct, limit);

            var data = _product.paginationProduct(start, limit);

            return View(data);
        }
    }
}

# Cấu hình Views

Tạo file Index.cshtml trong thư mục Views/Product
+ Views/Product/Index.cshtml

@model IEnumerable<Product>
@{Layout = "~/Views/Shared/_Layout.cshtml";}
<div class="row">
    <div class="col-md-8">
        <h2>Pagiantion Product</h2>
        <table class="table">
            <thead>
                <tr>
                    <th>Title</th>
                    <th>Image</th>
                    <th>Detail</th>
                    <th>Price</th>
                </tr>
            </thead>
            <tbody>
               @foreach(var item in Model)
               {
                   <tr>
                       <td>@item.Title</td>
                       <td>@item.UrlImage</td>
                       <td>@item.Detail</td>
                       <td>@item.Price</td>
                   </tr>
               }
            </tbody>
        </table>
        <ul class="pagination">
            @{
                int numberPage = ViewBag.numberPage;
                int pageCurrent = ViewBag.pageCurrent;
                int offset = 2;//number display page


                //config FirstLink
                if (pageCurrent > 1)
                {
                    int prevPage = pageCurrent - 1;
                    var PrevLink = new Dictionary<string, string> { { "page", prevPage.ToString() } };
                    <li><a asp-controller="Product" asp-action="Index" asp-all-route-data="PrevLink">Prev Link</a></li>
                }

                int from = pageCurrent - offset; 
                int to = pageCurrent + offset; 
                if (from <= 0)
                {
                    from = 1;
                    to = offset * 2;
                }

               
                if (to > numberPage)
                {
                    to = numberPage;
                }

                int i;
                for (i = from; i <= to; i++)
                {
                    var parms = new Dictionary<string, string>
                    {
                        { "page",i.ToString()}
                    };
                    if (pageCurrent == i)
                    {
                        <li class="active"><a asp-controller="Product" asp-action="Index" asp-all-route-data="parms">@i</a></li>
                    }
                    else
                    {
                        <li><a asp-controller="Product" asp-action="Index" asp-all-route-data="parms">@i</a></li>
                    }

                }
              
                if (pageCurrent < numberPage - (to / 2))
                {
                    <li><a>...</a></li>
                    var LastLink = new Dictionary<string, string> { { "page", numberPage.ToString() } };
                    <li><a asp-controller="Product" asp-action="Index" asp-all-route-data="LastLink">Last Link</a></li>
                }

                if (pageCurrent < numberPage)
                {
                    int nextPage = pageCurrent + 1;
                    var NextLink = new Dictionary<string, string> { { "page", nextPage.ToString() } };
                    <li><a asp-controller="Product" asp-action="Index" asp-all-route-data="NextLink">Next Link</a></li>
                }
            }
        </ul>
    </div>
</div>

+ Chỉnh sửa Startup.cs

app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Product}/{action=Index}/{id?}");
            });

# Demo Pagination ASP.NET Core 2.1

Pagination using ASP.NET Core 2.1

Pagination using ASP.NET Core 2.1

Github: Pagination using ASP.NET Core 2.1