In this article, I will show you how to filter a paged list (Blazorise DataGrid component) in an ABP Framework application with a Blazor user interface.
The sample application has been developed with Blazor as UI framework and SQL Server as database provider.
The source code of the completed application is available on GitHub.
The following tools are needed to run the solution.
- .NET 8.0 SDK
- vscode, Visual Studio 2022, or another compatible IDE.
- ABP Cli 8.0.0
- Install or update the ABP CLI:
dotnet tool install -g Volo.Abp.Cli || dotnet tool update -g Volo.Abp.Cli
- Use the following ABP CLI command to create a new Blazor ABP application:
abp new AbpFilter -u blazor -o AbpFilter
- Run the
AbpFilter.DbMigrator
application to apply the migrations and seed the initial data. - Run the
AbpFilter.HttpApi.Host
application to start the server-side. - Run the
AbpFilter.Blazor
application to start the Blazor UI project.
To have a simple BookStore application to test with, add the code from the BookStore Tutorial (Part1-2).
Add a BookFilter class to the Books folder of the Domain project
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace AbpFilter.Books
{
public class BookFilter
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? PublishDate { get; set; }
public string? Price { get; set; }
}
}
Add an IBookRepository interface to the Books folder of the Domain project.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AbpFilter.Domain.Books;
using Volo.Abp.Domain.Repositories;
namespace AbpFilter.Books
{
public interface IBookRepository : IRepository<Book, Guid>
{
Task<List<Book>> GetListAsync(int skipCount, int maxResultCount, string sorting = "Name", BookFilter? filter = null);
Task<int> GetTotalCountAsync(BookFilter filter);
}
}
Add a BookRepository class to the Books folder of the EntityFrameworkCore project.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using AbpFilter.Domain.Books;
using AbpFilter.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace AbpFilter.Books
{
public class BookRepository(IDbContextProvider<AbpFilterDbContext> dbContextProvider)
: EfCoreRepository<AbpFilterDbContext, Book, Guid>(dbContextProvider), IBookRepository
{
public async Task<List<Book>> GetListAsync(int skipCount, int maxResultCount, string sorting = "Name", BookFilter filter = null)
{
var dbSet = await GetDbSetAsync();
var books = await dbSet
.WhereIf(!filter.Id.IsNullOrWhiteSpace(), x => x.Id.ToString().Contains(filter.Id))
.WhereIf(!filter.Name.IsNullOrWhiteSpace(), x => x.Name.Contains(filter.Name))
.WhereIf(!filter.Price.IsNullOrWhiteSpace(), x => x.Price.ToString().Contains(filter.Price))
.WhereIf(!filter.PublishDate.IsNullOrWhiteSpace(), x => x.PublishDate.ToString().Contains(filter.PublishDate))
.OrderBy(sorting)
.Skip(skipCount)
.Take(maxResultCount)
.ToListAsync();
return books;
}
public async Task<int> GetTotalCountAsync(BookFilter filter)
{
var dbSet = await GetDbSetAsync();
var books = await dbSet
.WhereIf(!filter.Id.IsNullOrWhiteSpace(), x => x.Id.ToString().Contains(filter.Id))
.WhereIf(!filter.Name.IsNullOrWhiteSpace(), x => x.Name.Contains(filter.Name))
.WhereIf(!filter.Price.IsNullOrWhiteSpace(), x => x.Price.ToString().Contains(filter.Price))
.WhereIf(!filter.PublishDate.IsNullOrWhiteSpace(), x => x.PublishDate.ToString().Contains(filter.PublishDate))
.ToListAsync();
return books.Count;
}
}
}
Add a BookPagedAndSortedResultRequestDto class to the Books folder of the Application.Contracts project. This class inherits the PagedAndSortedResultRequestDto class.
using Volo.Abp.Application.Dtos;
namespace AbpFilter.Books
{
public class BookPagedAndSortedResultRequestDto : PagedAndSortedResultRequestDto
{
public string? Id { get; set; } = "";
public string? Name { get; set; } = "";
public string? PublishDate { get; set; } = "";
public string? Price { get; set; } = "";
}
}
Update the IBookAppService interface in the Books folder of the Application.Contracts project.
using System;
using Volo.Abp.Application.Services;
namespace AbpFilter.Books
{
public interface IBookAppService : ICrudAppService<BookDto, Guid, BookPagedAndSortedResultRequestDto, CreateUpdateBookDto>;
}
Add a BookAutoMapperProfile class to the Books folder of the Application project.
using AbpFilter.Application.Contracts.Books;
using AbpFilter.Domain.Books;
using AutoMapper;
namespace AbpFilter.Application.Books
{
public class BookAutoMapperProfile : Profile
{
public BookAutoMapperProfile()
{
CreateMap<BookPagedAndSortedResultRequestDto, BookFilter>();
}
}
}
Override the GetListAsync method of the BookAppService class in the Books folder of the Application project, as in the code below:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AbpFilter.Domain.Books;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace AbpFilter.Books
{
public class BookAppService(IBookRepository bookRepository)
: CrudAppService<Book, BookDto, Guid, BookPagedAndSortedResultRequestDto, CreateUpdateBookDto>(bookRepository),
IBookAppService
{
public override async Task<PagedResultDto<BookDto>> GetListAsync(BookPagedAndSortedResultRequestDto input)
{
var filter = ObjectMapper.Map<BookPagedAndSortedResultRequestDto, BookFilter>(input);
var sorting = (string.IsNullOrEmpty(input.Sorting) ? "Name DESC" : input.Sorting).Replace("ShortName", "Name");
var books = await bookRepository.GetListAsync(input.SkipCount, input.MaxResultCount, sorting, filter);
var totalCount = await bookRepository.GetTotalCountAsync(filter);
return new PagedResultDto<BookDto>(totalCount,ObjectMapper.Map<List<Book>, List<BookDto>>(books));
}
}
}
Override the DataGrid component of the Books.razor page in the Blazor project and Make sure you add the Filterable attribute and set it to true
@page "/books"
@using AbpFilter.Books
@inherits AbpCrudPageBase<AbpFilter.Books.IBookAppService, AbpFilter.Books.BookDto, Guid, AbpFilter.Books.BookPagedAndSortedResultRequestDto, AbpFilter.Books.CreateUpdateBookDto>
<Card>
<CardBody>
<DataGrid TItem="BookDto" Filterable="true" Data="Entities" ReadData="OnDataGridReadAsync" TotalItems="TotalCount" ShowPager="true" PageSize="PageSize">
<DataGridColumns>
<DataGridColumn TItem="BookDto" Field="@nameof(BookDto.Id)" Caption="Id"></DataGridColumn>
<DataGridColumn TItem="BookDto" Field="@nameof(BookDto.Name)" Caption="Name"></DataGridColumn>
<DataGridColumn TItem="BookDto" Field="@nameof(BookDto.PublishDate)" Caption="Publish date"></DataGridColumn>
<DataGridColumn TItem="BookDto" Field="@nameof(BookDto.Price)" Caption="Price"></DataGridColumn>
</DataGridColumns>
</DataGrid>
</CardBody>
</Card>
Override the UpdateGetListInputAsync and OnDataGridReadAsync methods as you can see below:
using System.Linq;
using System.Threading.Tasks;
using AbpFilter.Books;
using Blazorise.DataGrid;
using Volo.Abp.Application.Dtos;
using static System.String;
namespace AbpFilter.Blazor.Pages
{
public partial class Books
{
protected override Task UpdateGetListInputAsync()
{
if (GetListInput is ISortedResultRequest sortedResultRequestInput)
{
sortedResultRequestInput.Sorting = CurrentSorting;
}
if (GetListInput is IPagedResultRequest pagedResultRequestInput)
{
pagedResultRequestInput.SkipCount = (CurrentPage - 1) * PageSize;
}
if (GetListInput is ILimitedResultRequest limitedResultRequestInput)
{
limitedResultRequestInput.MaxResultCount = PageSize;
}
return Task.CompletedTask;
}
protected override Task OnDataGridReadAsync(DataGridReadDataEventArgs<BookDto> e)
{
var id = e.Columns.FirstOrDefault(c => c.SearchValue != null && c.Field == "Id");
GetListInput.Id = id != null && !IsNullOrEmpty(id.SearchValue.ToString()) ? id.SearchValue.ToString(): Empty;
var name = e.Columns.FirstOrDefault(c => c.SearchValue != null && c.Field == "Name");
GetListInput.Name = name != null && !IsNullOrEmpty(name.SearchValue.ToString()) ? name.SearchValue.ToString() : Empty;
var publishDate = e.Columns.FirstOrDefault(c => c.SearchValue != null && c.Field == "PublishDate");
GetListInput.PublishDate = publishDate != null && !IsNullOrEmpty(publishDate.SearchValue.ToString()) ? publishDate.SearchValue.ToString() : Empty;
var price = e.Columns.FirstOrDefault(c => c.SearchValue != null && c.Field == "Price");
GetListInput.Price = price != null && !IsNullOrEmpty(price.SearchValue.ToString()) ? price.SearchValue.ToString() :Empty;
return base.OnDataGridReadAsync(e);
}
}
}
Et voilà! You can now filter a standard paged list (Blazorise DataGrid component) in the ABP Framework.
Get the source code on GitHub.
Enjoy and have fun!