ABP Introduction Series (7) - Paging Implementation

Keywords: ASP.NET Front-end github

ABP Introductory Series Catalogue: Practical Exercise on Learning Abp Framework

After completing the addition, deletion and alteration of the task list, let's talk about the essential paging function.
First of all, I'm glad that ABP has encapsulated our paging implementation. It's really intimate.
Come on, let's take a look at how to use ABP to paginate in this section.

Definition of Paging Request DTO

Data Transfer Objects are used for data transmission in application layer and display layer.
An application service method is invoked by the incoming data transfer object (DTO) of the presentation layer. Then the application service executes some specific business logic through the domain object and returns the DTO to the presentation layer. In this way, the presentation layer and the domain layer are completely separated. In well-structured applications, the presentation layer does not directly use domain objects (warehouses, entities).

When we have paging requests in the presentation layer, we usually need to specify two parameters, one to indicate the number of pages and one to indicate the number of rows per page (usually with configuration file configuration).
Because paging is a very common function, when we have paging requests in the presentation layer, it's better to have DTO s to encapsulate these two parameters.
There is no such common class encapsulated for us in the ABP source code, but in the ABP Zero project, the corresponding paging Dto is defined.
The corresponding class diagram is as follows:

It can be seen that there are mainly four common DTO definitions:

  1. PagedInputDto: Paging request Dto
  2. PagedAndSortedInputDto: Paging sort Dto
  3. PagedSorted AndFiltered Input Dto: Paging sort filter Dto
  4. PagedAndFiltered Input Dto: Paging Filtered Dto

Is it practical that our paging is usually mixed with filtering sort?

It mainly defines the following main attributes:

  • MaxResultCount: Number of rows per page that can be read from the defined configuration.
  • SkipCount: Number of jumps. The general formula is SkipCount = PageMax ResultCount (number of pages and rows).
  • Filter: Filter string
  • Sorting: Sorting

Specific implementation is not detailed, I believe that carefully look at the class diagram, you can do it yourself. AbpZero defines these common Dtos under the Dto folder of the application service layer. The specific path is shown below.

How to Use Paging DTO

Take our task list as an example, we modify the GetTaskInputDto we created to inherit from PagedSorted AndFiltered InputDto, so that GetTaskInputDto has the attributes needed for paging sort filtering.

public class GetTasksInput : PagedSortedAndFilteredInputDto
{
    public TaskState? State { get; set; }

    public int? AssignedPersonId { get; set; }
}

3. Return Paging Result DTO

Abp has defined generic PagedResultDto for us to wrap the returned paging results. It mainly includes two attributes: int Total Count saves the total number and IReadOnlyList < T > Items saves the returned paging result set.

4. Implementation of Paging Logic in Application Service Layer

1. Add interface definition in ITaskAppService:
PagedResultDto<TaskDto> GetPagedTasks(GetTasksInput input);
2. Implement the interface in TaskAppService:

public PagedResultDto<TaskDto> GetPagedTasks(GetTasksInput input)
{
    //Preliminary filtration
    var query = _taskRepository.GetAll().Include(t => t.AssignedPerson)
        .WhereIf(input.State.HasValue, t => t.State == input.State.Value)
        .WhereIf(!input.Filter.IsNullOrEmpty(), t => t.Title.Contains(input.Filter))
        .WhereIf(input.AssignedPersonId.HasValue, t => t.AssignedPersonId == input.AssignedPersonId.Value);

    //sort
    query = !string.IsNullOrEmpty(input.Sorting) ? query.OrderBy(input.Sorting) : query.OrderByDescending(t => t.CreationTime);

    //Total number obtained
    var tasksCount = query.Count();
    //Default Paging Method
    //var taskList = query.Skip(input.SkipCount).Take(input.MaxResultCount).ToList();

    //ABP provides PageBy paging as an extension method
    var taskList = query.PageBy(input).ToList();

    return new PagedResultDto<TaskDto>(tasksCount,taskList.MapTo<List<TaskDto>>());
}

Paging is implemented simply by filtering, sorting, and then paging. Finally, PagedResultDto is used to encapsulate the results of paging.
Carefully, you may find two methods where If and PageBy that you haven't used in Linq before. Yes, this is the extension method provided by ABP. If you're interested, look at the source code. QueryableExtensions The specific implementation, in fact, is very simple, but we usually use linq is not necessarily able to imagine.

Here are some questions:

  1. How many queries have been made in this code?
  2. What paging techniques are used in the code? (Real paging? False Paging?

5. Paging front-end using X.PagedList

There are a series of open source implementations for front-end paging in Asp.Net Mvc, and I use open source X.PagedList paging in my Demo. For specific source code, please refer to X.PagedList GitHub.

1. Install the X.PagedList.Mvc Nuget package in your Web project by yourself

2. Use the method provided by X.PagedList in Controller to construct paging results for front-end use
Because we have implemented the paging logic manually in the application service layer, we need to construct the StaticPagedList as the return result according to the official example of X.PagedList.

 public ActionResult PagedList(int? page)
 {
     //linage
     var pageSize = 5;
     var pageNumber = page ?? 1;//How many pages

     var filter = new GetTasksInput
     {
         SkipCount = (pageNumber - 1) * pageSize,//Ignore the number
         MaxResultCount = pageSize
     };
     var result = _taskAppService.GetPagedTasks(filter);

     //Paging logic has been manually completed in the application service layer, so the paging results need to be constructed manually.
     var onePageOfTasks = new StaticPagedList<TaskDto>(result.Items, pageNumber, pageSize, result.TotalCount);
     //Put paging results into ViewBag for View use
     ViewBag.OnePageOfTasks = onePageOfTasks;

     return View();
}

You can see from the code that we constructed the paging results provided by X.PagedList and put them into ViewBag for view use.

3. Adding Paging Control in View
The code for the PagedList view is as follows:

@using X.PagedList.Mvc;
@using Abp.Web.Mvc.Extensions
@using X.PagedList; 
<link href="~/Content/PagedList.css" rel="stylesheet" />
<ul class="list-group">
    @foreach (var task in ViewBag.OnePageOfTasks)
    {
        <li class="list-group-item">
            <div class="btn-group pull-right">
                <button type="button" class="btn btn-info">Edit</button>
                <button type="button" class="btn btn-success">Delete</button>
            </div>

            <div class="media">
                <a class="media-left" href="#">
                    @*<i class="fa @Model.GetTaskLable(task) fa-3x"></i>*@
                </a>
                <div class="media-body">
                    <h4 class="media-heading">@task.Title</h4>
                    <span class="text-muted">@task.CreationTime.ToString("yyyy-MM-dd HH:mm:ss")</span>
                </div>
            </div>

        </li>
    }
</ul>

@Html.PagedListPager((IPagedList)ViewBag.OnePageOfTasks, page => Url.Action("PagedList", new { page }))

The last line of code is used to generate paging controls.

The final effect is as follows:

summary

This section mainly explains how to use ABP for background paging, and explains the realization of ABP background paging logic incidentally. It also demonstrates how to use X.PagedList for front-end paging.

Posted by Threepwood on Thu, 21 Mar 2019 08:18:52 -0700