如何在ASP.NET Core中建立有效的分页
目录
介绍
背景
创建项目
在后端处理分页
创建分页UI控件
添加搜索过滤器
自定义分页UI控件
改善性能
改善搜寻逻辑
- 下载样本-1.6 MB
介绍
本文将解释如何使用分页来仅检索所需数量的记录,并显示参考总记录的分页控件。
背景
最有可能遇到了这个问题,您需要从包含数千个或更多记录的数据源中列出几行记录,但随后注意到分页是提高站点性能的重要因素。从过滤数据到从数据库中选择相关记录到显示页面调度控件,要构建一个可靠的页面调度系统,需要考虑一些很重要的步骤。
创建项目
我将使用VS2019附带的默认ASP.NET Core 2.2项目模板,因此只需创建基本的ASP.NET Core 2.2项目并在此处继续阅读。
在深入探讨分页之前,我们需要为记录创建一个数据源。我们的数据源必须包含很多记录,以便我们可以看到分页控件的真正好处。为了使注意力集中在分页主题上,我将使用框架中已包含的项目列表(CultureInfo)。
打开Pages/Index.cshtml.cs并添加数据源,如下所示:
public class IndexModel : PageModel
{ public CultureInfo[] CulturesList { get; set; }private CultureInfo[] Cultures { get; set; }public IndexModel(){//this will act as the main data source for our projectCultures = CultureInfo.GetCultures(CultureTypes.AllCultures);}public void OnGet(){CulturesList = Cultures;}
}
打开Pages/Index.cshtml 并添加以下代码以显示区域性列表:
<table class="table table-striped"><thead><tr><th>LCID</th><th>English Name</th><th>Native Name</th><th>Culture types</th></tr></thead><tbody>@foreach (var c in Model.CulturesList){<tr><td>@c.LCID</td><td>@c.EnglishName</td><td>@c.NativeName</td><td>@c.CultureTypes</td></tr>}</tbody>
</table>
运行应用程序以查看第一个结果:
在后端处理分页
如您所见,我们正在将所有记录发送到视图,但这不是一种有效的编程方式,因此我们将限制所选记录的数量,以将少量数据发送到视图。基本上,我们需要两个用于分页的变量;
- 页码:用于指示请求的页码的变量
- 页面大小:一个变量,指示应该一次选择的记录总数
稍后,我们还将添加更多变量以进行过滤。
返回Pages/Index.cshtml.cs文件,定义变量并修改OnGet,所以我们的新IndexModel看起来如下所示:
public class IndexModel : PageModel
{ public IList<CultureInfo> CulturesList { get; set; }private CultureInfo[] Cultures { get; set; }//page number variable[BindProperty(SupportsGet = true)]public int P { get; set; } = 1;//page size variable[BindProperty(SupportsGet = true)]public int S { get; set; } = 10;public IndexModel(){//this will act as the main data source for our projectCultures = CultureInfo.GetCultures(CultureTypes.AllCultures);}public void OnGet(){CulturesList = Cultures//make sure to order items before paging.OrderBy(x=>x.EnglishName)//skip items before current page.Skip((P-1)*S)//take only 10 (page size) items.Take(S)//call ToList() at the end to execute the query and return the result set.ToList();}
}
运行该应用程序,您将仅看到前10条记录。
创建分页UI控件
Bootstrap提供了一个非常不错的分页UI控件,但它仅呈现HTML元素,并且仍然需要进行大量工作才能知道在控件内呈现什么内容以及如何呈现,例如,记录总数,最大显示页数,搜索过滤器,根据当前页面索引等启用/禁用上一个——下一个按钮。
我将使用LazZiya.TagHelpers nuget包中的页面标记助手,它将为我们完成所有艰苦的工作。:)
PagingTagHelper 基本上需要这些参数:
- page-no:当前页码的必需int变量
- total-records:数据源中的总记录数所必需的int
- query-string-value:string值,如果URL中包含搜索过滤器,则为必填
- page-size:可选int(默认为10)
- query-string-key-page-no:可选,string指示页码的查询字符串键名称。默认值为"p",我们将不使用它,因为我们在后端定义了相同的键名。
- query-string-key-page-size:可选,string指示页面大小的查询字符串键名称。默认值为"s",所以我们不会使用它,因为我们也在后端定义了相同的键名。
在此处阅读有关PagingTagHelper的更多信息。
因此,在添加页面标记帮助器之前,我们需要再添加一个变量来处理后端的总记录数:
//total number of records
public int TotalRecords { get; set; } = 0;public void OnGet()
{TotalRecords = Cultures.Count();CulturesList = Cultures//make sure to order items before paging.OrderBy(x=>x.EnglishName)//skip items before current page.Skip((P-1)*S)//take only 10 (page size) items.Take(S)//call ToList() at the end to execute the query and return the result set.ToList();
}
现在,我们准备使用分页标记帮助器。
使用软件包管理器控制台安装LazZiya.TagHelpers nuget软件包(请确保下载最新版本):
Install-Package LazZiya.TagHelpers -Version 2.2.1
或使用nuget包管理器UI:
添加LazZiya.TagHelpers到_ViewImports.cshtml页面:
@addTagHelper *, LazZiya.TagHelpers
将页面标记帮助程序代码添加到表下方的Index.cshtml视图中:
<paging page-no="Model.P"page-size="Model.S"total-records="Model.TotalRecords">
</paging>
稍后,我们将在添加一些搜索过滤器之后添加query-string-value,现在,运行该应用并在其基本设置中测试分页控件:
添加搜索过滤器
记录的基本列表已完成,现在我们将添加一些搜索过滤器以具有更多功能列表。
首先,让我们将基本的文本搜索逻辑添加到后端:
//variable for text search
[BindProperty(SupportsGet = true)]
public string Q { get; set; } = string.Empty;public void OnGet()
{var query = Cultures//search in EnglishName and NativeName.Where(x =>x.EnglishName.Contains(Q, StringComparison.OrdinalIgnoreCase) ||x.NativeName.Contains(Q, StringComparison.OrdinalIgnoreCase));//count records that returns after the searchTotalRecords = query.Count();CulturesList = query//make sure to order items before paging.OrderBy(x => x.EnglishName)//skip items before current page.Skip((P - 1) * S)//take only 10 (page size) items.Take(S)//call ToList() at the end to execute the query and return the result set.ToList();
}
我们定义了一个名为"Q"的string变量,该变量将分配给搜索文本框。此外,我们修改了逻辑,以便TotalRecords值返回搜索后的记录数。
现在我们可以将搜索表单添加到前端:
<form method="get" class="form-inline"><input asp-for="Q" class="form-control" /><button type="submit" class="btn btn-primary">Search</button>
</form>
确保form方法是"get"因为我们在后端定位目标OnGet()方法,这将使我们能够共享任何编号页面的URL。
运行应用程序并测试搜索:
搜索效果很好,但是如果单击另一个页码,则会丢失搜索关键字!为了使所有查询字符串参数都包含在带编号的页面URL中,我们需要添加query-string-value到标签帮助器中:
<paging page-no="Model.P"page-size="Model.S"total-records="Model.TotalRecords"query-string-value="@(Request.QueryString.Value)">
</paging>
现在,搜索和分页可以很好地协同工作。
自定义分页UI控件
可以通过添加更多控件(如页面总数标签,总记录标签和页面大小控件)来自定义我们的页面标记助手,并修改如下的页面标记助手代码以获取更多详细信息:
<paging page-no="Model.P"page-size="Model.S"total-records="Model.TotalRecords"query-string-value="@(Request.QueryString.Value)"show-prev-next="true"show-total-pages="true"show-total-records="true"show-page-size-nav="true"show-first-numbered-page="true"show-last-numbered-page="true">
</paging>
现在我们有了更多功能的分页控件:
改善性能
到现在为止,我们将返回CultureInfo项列表,但是在表中仅显示了几个字段!因此,我们可以通过返回仅包含显示字段的对象列表来改善内存/带宽的使用。
创建一个名为CultureItem的新类,并修改搜索逻辑以返回CultureItem的列表,而不是CultureInfo:
//object that contains only displayed fields
public class CultureItem
{public int LCID { get; set; }public string EnglishName { get; set; }public string NativeName { get; set; }public CultureTypes CultureTypes { get; set; }
}//return list of CultureItem
public IList<CultureItem> CulturesList { get; set; }public void OnGet()
{var query = Cultures//search in EnglishName and NativeName.Where(x =>x.EnglishName.Contains(Q, StringComparison.OrdinalIgnoreCase) ||x.NativeName.Contains(Q, StringComparison.OrdinalIgnoreCase))//map the selected fields to our new object.Select(x => new CultureItem{LCID = x.LCID,EnglishName = x.EnglishName,NativeName = x.NativeName,CultureTypes = x.CultureTypes});//count records that returns after the searchTotalRecords = query.Count();CulturesList = query//make sure to order items before paging.OrderBy(x => x.EnglishName)//skip items before current page.Skip((P - 1) * S)//take only 10 (page size) items.Take(S)//call ToList() at the end to execute the query and return the result set</span>.ToList();
}
改善搜寻逻辑
我们将关键字用作搜索中的一个文本字符串,我们可以通过拆分搜索关键字并删除空白和重复项来改善查询效果:
var _keyWords = Q.Split(new[] { ' ', ',', ':' },
StringSplitOptions.RemoveEmptyEntries).Distinct();
当使用MSSqlDb之类的数据库并在可为空的字段中进行搜索时,如果搜索到的字段为null,则可能会出现异常,为了避免在null字段中进行搜索,我们可以在搜索逻辑中添加null检查条件。
var query = Cultures//search in EnglishName and NativeName.Where(x => _keyWords.Any(kw =>(x.EnglishName!=null && x.EnglishName.Contains(kw, StringComparison.OrdinalIgnoreCase)) ||(x.NativeName != null && x.NativeName.Contains(kw, StringComparison.OrdinalIgnoreCase))))
通过在搜索数据库时使用AsNoTracking(),甚至可以进一步提高性能,因此框架不会继续跟踪所选实体,这将有助于释放一些内存。
如何在ASP.NET Core中建立有效的分页相关推荐
- 如何在 ASP.NET Core 中使用 HttpClientFactory ?
ASP.Net Core 是一个开源的,跨平台的,轻量级模块化框架,可用它来构建高性能的Web程序,这篇文章我们将会讨论如何在 ASP.Net Core 中使用 HttpClientFactory. ...
- 如何在 ASP.Net Core 中使用 Autofac
依赖注入可以有效的实现对象之间的 松耦合 并能够实现代码的可测试和可维护性,ASP.Net Core 提供了一个极简版的容器实现对 依赖注入 的原生支持,然而内置的依赖注入容器相比成熟的 依赖注入容器 ...
- 如何在 ASP.Net Core 中使用 Lamar
ASP.Net Core 自带了一个极简的 开箱即用 的依赖注入容器,实际上,你还可以使用第三方的 依赖注入容器 来替代它,依赖注入是一种设计模式,它能够有效的实现对象之间的解耦并有利于提高单元测试和 ...
- 如何在 ASP.Net Core 中使用 MediatR
MediatR 是一个 中介者模式 的.NET开源实现, 中介者模式 管控了一组对象之间的相互通讯并有效的减少了对象之间错综复杂的相互依赖,在 中介者模式 中,一个对象不需要直接和另一个对象进行通讯, ...
- 如何在 ASP.Net Core 中对接 WCF
在 REST API 出现之前,SOAP (Simple Object Access Protocol) 一直都是基于 web 的标准协议,虽然现在 REST 大行其道,但在平时开发中总会遇到对接第三 ...
- 如何在 ASP.Net Core 中使用 NCache
虽然 ASP.Net Core 中缺少 Cache 对象,但它引入了三种不同的cache方式. 内存缓存 分布式缓存 Response缓存 Alachisoft 公司提供了一个开源项目 NCache, ...
- 如何在 ASP.Net Core 中使用 Configuration Provider
ASP.NET Core 是一个开源的,跨平台的,精简的模块化框架,可用于构建高性能,可扩展的web应用程序, ASP.NET Core 中的数据配置常用 k-v 的形式存储,值得注意的是,新的数据配 ...
- 如何在 ASP.Net Core 中使用 Serilog
记录日志的一个作用就是方便对应用程序进行跟踪和排错调查,在实际应用上都是引入 日志框架,但如果你的 日志文件 包含非结构化的数据,那么查询起来将是一个噩梦,所以需要在记录日志的时候采用结构化方式. 将 ...
- 如何在 ASP.NET Core 中使用 URL Rewriting 中间件
URL rewriting 是根据预先配置好的一组规则去修改 request url,值得注意的是:URL Rewriting 的重写功能和 url 重定向 是两个概念,本篇我们就来讨论下如何在 AS ...
最新文章
- 机器学习(MACHINE LEARNING)使用ARIMA进行时间序列预测
- href 和 src 的区别
- Java方法中的参数太多,第3部分:构建器模式
- java对mysql的简单操作的综合运用——登录+注册+修改密码
- devops是运维吗_您是DevOps的合适人选吗?
- Safari 搜寻引擎被 Yahoo 绑架,试试这 4 种解决方法
- Linux下音乐播放器的实现
- Java 10大骚操作写法,亮瞎boss的双眼!
- KUKA机器人视觉1
- GitHub Actions 入门教程
- VUE中的img的:src动态加载图片的问题,require也不能随便用
- 路由器——计算机网络
- windows系统使用cmd命令打开谷歌浏览器并设置用户资料方法步骤
- 使用Apriori算法寻找频繁样式(Frequent Patterns)
- 18.10.20日报
- SpringCloud版本Hoxton SR5 --- 第七讲:SpringCloud Config 分布式配置中心+整合bus、rabbitmq、actuator
- Unity3D如何快速入门
- 4.1 -Springboot 编写http接口
- 文件路径最好使用正斜杠。使用反斜杠可能在unix系统中访问不到文件。
- 高效率mesh转深度图python代码
热门文章
- android申请多个运行时权限,Android 6.0(API 23) 运行时权限(二)之权限申请
- vim linux python3,VIM:在python-mode中使用python3解释器
- 中国风冬日节日必备梅花PNG免扣素材
- 配色方案专辑上线,宠溺设计师的好素材!
- 优秀案例UI素材模板|深层解析iPhone手机APP页面怎么设计?
- 有效提高作品率的UI设计技巧,你知道多少?
- 乐高百变工程旋转飞椅知识点_每日一个知识点:关于磁盘的一些事儿
- 拓扑检查中的一些问题(为啥没自相交)
- Maple:把计算结果保存出来
- Dentry negativity/negative dentry