将较大的内容拆分为不同的页面称为分页。这种方法大大增强了用户体验并加快了网页的加载速度。此示例将演示如何使用 .NET 创建分页 API,并将 MySQL 用作数据库。
dotnet new webapi -o dotnet_api -n App
创建一个名为“example”的测试数据库,并运行database.sql文件以导入表和数据。
├─ Controllers
│ └─ ProductController.cs
├─ Models
│ ├─ DataContext.cs
│ └─ Product.cs
├─ wwwroot
│ └─ index.html
├─ Util.cs
├─ Program.cs
├─ App.csproj
└─ appsettings.json
此文件是 .NET 项目配置文件。我们在此处添加了包。MySql.EntityFrameworkCore
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MySql.EntityFrameworkCore" Version="8.0.0" />
</ItemGroup>
</Project>
这是包含数据库连接信息的 .NET 应用程序配置文件。
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"Database": "server=localhost;port=3306;database=example;user id=root;password=;"
}
}
此文件是 .NET API 应用程序的主要入口点。
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext<App.Models.DataContext>(options => options.UseMySQL(builder.Configuration.GetConnectionString("Database")));
var app = builder.Build();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseRouting();
app.MapControllers();
app.Run();
此文件定义了类的扩展方法,用于实现实体框架的动态列排序。OrderBy()IQueryable
using System.Linq.Expressions;
using System.Reflection;
namespace App
{
public static class Util
{
public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> query, string column, string direction)
{
var type = typeof(TEntity);
var parameter = Expression.Parameter(type);
var property = type.GetProperty(column, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
var member = Expression.MakeMemberAccess(parameter, property);
var lamda = Expression.Lambda(member, parameter);
var method = direction == "desc" ? "OrderByDescending" : "OrderBy";
var expression = Expression.Call(typeof(Queryable), method, new Type[] { type, property.PropertyType }, query.Expression, Expression.Quote(lamda));
return query.Provider.CreateQuery<TEntity>(expression);
}
}
}
在 .NET 应用程序中使用实体框架 (EF) 时,这是必需的文件。它用于将数据库中的表和列信息映射到实体。
using Microsoft.EntityFrameworkCore;
namespace App.Models
{
public partial class DataContext : DbContext
{
public virtual DbSet<Product> Product { get; set; }
public DataContext()
{
}
public DataContext(DbContextOptions<DataContext> options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>(entity =>
{
entity.ToTable("Product");
entity.HasKey(e => e.Id);
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.Name).HasColumnName("name").HasMaxLength(50).IsUnicode(false);
entity.Property(e => e.Price).HasColumnName("price").HasColumnType("decimal(12,2)");
});
}
}
}
此文件定义映射到名为“Product”的数据库表的模型信息。
using System.ComponentModel.DataAnnotations;
namespace App.Models
{
public partial class Product
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
此文件用于处理传入的请求并为客户端生成分页数据。
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Mvc;
using App.Models;
namespace App.Controllers
{
public class ProductController : Controller
{
private readonly DataContext _context;
public ProductController(DataContext context)
{
_context = context;
}
[HttpGet("api/products")]
public async Task<IActionResult> Index()
{
int page = Request.Query["page"].Any() ? Convert.ToInt32(Request.Query["page"]) : 1;
int size = Request.Query["size"].Any() ? Convert.ToInt32(Request.Query["size"]) : 10;
string order = Request.Query["order"].Any() ? Request.Query["order"].First() : "Id";
string direction = Request.Query["direction"].Any() ? Request.Query["direction"].First() : "asc";
var query = _context.Product.Select(e => new {
Id = e.Id,
Name = e.Name,
Price = e.Price
});
query = query.OrderBy(order, direction);
var products = await query.Skip((page - 1) * size).Take(size).ToListAsync();
return Ok(products);
}
}
}
我们没有手动输入 URL 来测试我们的 API,而是使用此文件来创建链接以便于测试。
<!DOCTYPE html>
<head>
</head>
<body>
<ul>
<li><a target="_blank" href="/api/products">Default</a></li>
<li><a target="_blank" href="/api/products?page=2">Page 2</a></li>
<li><a target="_blank" href="/api/products?page=2&size=25">Page 2 and Size 25</a></li>
<li><a target="_blank" href="/api/products?page=2&size=25&order=name">Page 2 and Size 25 and Order by name</a></li>
<li><a target="_blank" href="/api/products?page=2&size=25&order=name&direction=desc">Page 2 and Size 25 and Order by name descending</a></li>
</ul>
</body>
</html>
dotnet run
打开 Web 浏览器并转到 http://localhost:5122
您将找到此测试页面。
单击“默认”链接,它将打开 URLhttp://localhost:5122/api/products
API 将返回具有默认参数(page = 1 和 size = 10)的分页数据。
单击“第 2 页”链接,它将打开 URLhttp://localhost:5122/api/products?page=2
API 将在第二页上返回分页数据,从产品 ID 11 开始
单击“第 2 页和大小 25”链接,它将打开 URLhttp://localhost:5122/api/products?page=2&size=25
由于页面大小为 25,因此 API 将从产品 ID 26 开始,在第二个页面上返回分页数据。
单击“第 2 页和大小 25 并按名称排序”链接,它将打开 URLhttp://localhost:5122/api/products?page=2&size=25&order=name
API 将在第二页上返回分页数据,但产品顺序基于产品名称。
单击“第 2 页和大小 25 并按名称降序排序”链接,它将打开 URLhttp://localhost:5122/api/products?page=2&size=25&order=name&direction=desc
API 将在第二页上返回分页数据,但产品顺序基于产品名称的降序。
在本文中,你学习了如何利用实体框架轻松实现 .NET 应用程序的分页 API。分页方法将增强用户体验并加快 .NET API 的速度。
源代码获取:公众号回复消息【code:78289
】