Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
S

Sieve

> 编程语言
Open source

⚗️ Clean & extensible Sorting, Filtering, and Pagination for ASP.NET Core

1.3K stars0 likes0 views
WebsiteGitHub

About

⚗️ Clean & extensible Sorting, Filtering, and Pagination for ASP.NET Core

Sieve

⚗️ Sieve is a simple, clean, and extensible framework for .NET Core that adds sorting, filtering, and pagination functionality out of the box. Most common use case would be for serving ASP.NET Core GET queries. Get Sieve on nuget

Usage for ASP.NET Core

In this example, consider an app with a Post entity. We'll use Sieve to add sorting, filtering, and pagination capabilities when GET-ing all available posts.

1. Add required services

Inject the SieveProcessor service. So in Startup.cs add:

csharp
services.AddScoped();

2. Tell Sieve which properties you'd like to sort/filter in your models

Sieve will only sort/filter properties that have the attribute [Sieve(CanSort = true, CanFilter = true)] on them (they don't have to be both true). So for our Post entity model example:

csharp
public int Id { get; set; }

[Sieve(CanFilter = true, CanSort = true)]
public string Title { get; set; }

[Sieve(CanFilter = true, CanSort = true)]
public int LikeCount { get; set; }

[Sieve(CanFilter = true, CanSort = true)]
public int CommentCount { get; set; }

[Sieve(CanFilter = true, CanSort = true, Name = "created")]
public DateTimeOffset DateCreated { get; set; } = DateTimeOffset.UtcNow;

There is also the Name parameter that you can use to have a different name for use by clients.

Alternatively, you can use Fluent API to do the same. This is especially useful if you don't want to use attributes or have multiple APIs.

3. Get sort/filter/page queries by using the Sieve model in your controllers

In the action that handles returning Posts, use SieveModel to get the sort/filter/page query. Apply it to your data by injecting SieveProcessor into the controller and using its Apply method. So for instance:

csharp
[HttpGet]
public JsonResult GetPosts(SieveModel sieveModel) 
{
    var result = _dbContext.Posts.AsNoTracking(); // Makes read-only queries faster
    result = _sieveProcessor.Apply(sieveModel, result); // Returns `result` after applying the sort/filter/page query in `SieveModel` to it
    return Json(result.ToList());
}

You can also explicitly specify if only filtering, sorting, and/or pagination should be applied via optional arguments.

4. Send a request

Send a request

Add custom sort/filter methods

If you want to add custom sort/filter methods, inject ISieveCustomSortMethods or ISieveCustomFilterMethods with the implementation being a class that has custom sort/filter methods that Sieve will search through.

For instance:

csharp
services.AddScoped();
services.AddScoped();

Where SieveCustomSortMethodsOfPosts for example is:

…

And SieveCustomFilterMethods:

csharp
public class SieveCustomFilterMethods : ISieveCustomFilterMethods
{
    public IQueryable IsNew(IQueryable source, string op, string[] values) // The method is given the {Operator} & {Value}
    {
        var result = source.Where(p => p.LikeCount 
    }

    public IQueryable Latest(IQueryable source, string op, string[] values) where T : BaseEntity // Generic functions are allowed too
    {
        var result = source.Where(c => c.DateCreated > DateTimeOffset.UtcNow.AddDays(-14));
        return result;
    }
}

Configure Sieve

Use the ASP.NET Core options pattern with SieveOptions to tell Sieve where to look for configuration. For example:

csharp
services.Configure(Configuration.GetSection("Sieve"));

Then you can add the configuration:

json
{
    "Sieve": {
        "CaseSensitive": "boolean: should property names be case-sensitive? Defaults to false",
        "DefaultPageSize": "int number: optional number to fallback to when no page argument is given. Set 10, Title@=awesome title,     // filter to posts with more than 10 likes, and a title that contains the phrase "awesome title"
&page=      1                                       // get the first page...
&pageSize=  10                                      // ...which contains 10 posts

More formally:

  • sorts is a comma-delimited ordered list of property names to sort by. Adding a - before the name switches to sorting descendingly.
  • filters is a comma-delimited list of {Name}{Operator}{Value} where
    • {Name} is the name of a property with the Sieve attribute or the name of a custom filter method for TEntity
      • You can also have multiple names (for OR logic) by enclosing them in brackets and using a pipe delimiter, eg. (LikeCount|CommentCount)>10 asks if LikeCount or CommentCount is >10
    • {Operator} is one of the Operators
    • {Value} is the value to use for filtering
      • You can also have multiple values (for OR logic) by using a pipe delimiter, eg. Title@=new|hot will return posts with titles that contain the text "new" or "hot"
  • page is the number of page to return
  • pageSize is the number of items returned per page

Notes:

  • You can use backslashes to escape special characters and sequences:
    • commas: Title@=some\,title makes a match with "some,title"
    • pipes: Title@=some\|title makes a match with "some|title"
    • null values: Title@=\null will search for items with title equal to "null" (not a missing value, but "null"-string literally)
  • You can have spaces anywhere except within {Name} or {Operator} fields
  • If you need to look at the data before applying pagination (eg. get total count), use the optional paramters on Apply to defer pagination (an example)
  • Here's a good example on how to work with enumerables
  • Another example on how to do OR logic

Nested objects

You can filter/sort on a nested object's property by marking the property using the Fluent API. Marking via attributes not currently supported.

For example, using this object model:

csharp
public class Post {
    public User Creator { get; set; }
}

public class User {
    public string Name { get; set; }
}

Mark Post.User to be filterable:

csharp
// in MapProperties
mapper.Property(p => p.Creator.Name)
    .CanFilter();

Now you can make requests such as: filters=User.Name==specific_name.

Creating your own DSL

You can replace this DSL with your own (eg. use JSON instead) by implementing an ISieveModel. You can use the default SieveModel for reference.

Operators

Operator Meaning
== Equals
!= Not equals
> Greater than
= Greater than or equal to
` options,
    ISieveCustomSortMethods customSortMethods, 
    ISieveCustomFilterMethods customFilterMethods) 
    : base(options, customSortMethods, customFilterMethods)
{
}

protected override SievePropertyMapper MapProperties(SievePropertyMapper mapper)
{
    mapper.Property(p => p.Title)
        .CanFilter()
        .HasName("a_different_query_name_here");

    mapper.Property(p => p.CommentCount)
        .CanSort();

    mapper.Property(p => p.DateCreated)
        .CanSort()
        .CanFilter()
        .HasName("created_on");

    return mapper;
}

}


Now you should inject the new class instead:
```C#
services.AddScoped();

Find More on Sieve's Fluent API here.

Modular Fluent API configuration

Adding all fluent mappings directly in the processor can become unwieldy on larger projects. It can also clash with vertical architectures. To enable functional grouping of mappings the ISieveConfiguration interface was created together with extensions to the default mapper.

csharp
public class SieveConfigurationForPost : ISieveConfiguration
{
    public void Configure(SievePropertyMapper mapper)
    {
        mapper.Property(p => p.Title)
            .CanFilter()
            .HasName("a_different_query_name_here");

        mapper.Property(p => p.CommentCount)
            .CanSort();

        mapper.Property(p => p.DateCreated)
            .CanSort()
            .CanFilter()
            .HasName("created_on");

        return mapper;
    }
}

With the processor simplified to:

csharp
public class ApplicationSieveProcessor : SieveProcessor
{
    public ApplicationSieveProcessor(
        IOptions options, 
        ISieveCustomSortMethods customSortMethods, 
        ISieveCustomFilterMethods customFilterMethods) 
        : base(options, customSortMethods, customFilterMethods)
    {
    }

    protected override SievePropertyMapper MapProperties(SievePropertyMapper mapper)
    {
        return mapper
            .ApplyConfiguration()
            .ApplyConfiguration();       
    }
}

There is also the option to scan and add all configurations for a given assembly

csharp
public class ApplicationSieveProcessor : SieveProcessor
{
    public ApplicationSieveProcessor(
        IOptions options, 
        ISieveCustomSortMethods customSortMethods, 
        ISieveCustomFilterMethods customFilterMethods) 
        : base(options, customSortMethods, customFilterMethods)
    {
    }

    protected override SievePropertyMapper MapProperties(SievePropertyMapper mapper)
    {
        return mapper.ApplyConfigurationsFromAssembly(typeof(ApplicationSieveProcessor).Assembly);            
    }
}

Upgrading to v2.2.0

2.2.0 introduced OR logic for filter values. This means your custom filters will need to accept multiple values rather than just the one.

  • In all your custom filter methods, change the last argument to be a string[] values instead of string value
  • The first value can then be found to be values[0] rather than value
  • Multiple values will be present if the client uses OR logic

Upgrading from v1.* to v2.*

  • Changes to the SieveProcessor API:
    • ApplyAll is now Apply
    • ApplyFiltering, ApplySorting, and ApplyPagination are now depricated - instead you can use optional arguments on Apply to achieve the same
  • Instead of just removing commas from {Value}s, you'll also need to remove brackets and pipes

License & Contributing

Sieve is licensed under Apache 2.0. Any contributions highly appreciated!

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

C#asp-net-core-mvcaspnetcorefilternetcore2

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言