Summary
Today, I’m presenting to you, automatic filterin in AspNetCore Web Applications. That basicly converts Query String to LINQ without writing any of code, isn’t it amazing? Let’s follow this paper to understand that:
Problem
Let’s understand what is the problem and what will be automated. Think about you have a Blog entity like below:
public class Blog
{
public string BlogId { get; set; }
public int CategoryId { get; set; }
public int Priority { get; set; }
public bool IsPublished { get; set; }
public DateTime PublishDate { get; set; }
}
And think about you have a DTO to filter Blogs:
public class BlogFilterDto
{
public int CategoryId { get; set; }
public int Priority { get; set; }
public bool? IsPublished { get; set; }
public DateTime PublishDate { get; set; }
}
Now, this dto parameters comes from QueryString and it is used to filter Blogs in Controller via classical way:
[Route("api/[controller]")]
[ApiController]
public class BlogsController : ControllerBase
{
[HttpGet]
public async Task<IActionResult> Get([FromQuery]BlogFilterDto filter)
{
var db = new MyDbContext();
var query = db.Blogs;
if (filter.CategoryId != null)
query = query.Where(x => x.CategoryId == filter.CategoryId);
if (filter.IsPublished != null)
query = query.Where(x => x.IsPublished == filter.IsPublished);
if (filter.Priority != null)
query = query.Where(x => x.Priority == filter.Priority);
if (filter.PublishDate != null)
query = query.Where(x => x.PublishDate == filter.PublishDate);
var list = query.ToList();
return Ok(list);
}
}
Uhh, it is too much painful and compicated codes and stuffs.
Solution
There is a lot of way to solve this problem like reflection but the main point is keep conversion to dabase queries ability. That means we need to generate expressions from properties. It’s not logically right, to do this for each model. That’s why I created a library that converts properties to Expressions that can be applied on Entity Framework IQuaryable. That is AutoFilterer
AutoFilterer
Firstly, add AutoFilterer to your project from NuGet. You can visit wiki page to read more detailed installation and usage documentations.
Afterall, go your DTO and inherit from FilterBase class.
public class BlogFilterDto : FilterBase<Blog>
{
public int CategoryId { get; set; }
public int Priority { get; set; }
public bool? IsPublished { get; set; }
public DateTime PublishDate { get; set; }
}
And, go back to your controller and remove all the stuffs and just use ApplyFilterTo() method to generate expression and apply to DbSet. That’s it. It’s amazing, everything works easily with a clean controller code or repository code or whatever you say…
[Route("api/[controller]")]
[ApiController]
public class BlogsController : ControllerBase
{
// api/Blogs
// api/Blogs?categoryId=8
// api/Blogs?categoryId=8&isPublished=False
// api/Blogs?priority=2
[HttpGet]
public async Task<IActionResult> Get([FromQuery]BlogFilterDto filter)
{
var db = new MyDbContext();
var list = filter.ApplyFilterTo(db.Blogs).ToList();
return Ok(list);
}
}
Advanced configurations are made in your DTO with attributes. That keeps your code clean and readable with an amazing way! You can use this library in any platform, it’s for only Web API. You can use it in MVC projects with returning `View()` instead of `Ok()`
Advaned Options
For more feature, like Pagination, Range filtering, string search, you can find instructions from GitHub Page