romaklayt.DynamicFilter.Binder.Net
2.5.9
dotnet add package romaklayt.DynamicFilter.Binder.Net --version 2.5.9
NuGet\Install-Package romaklayt.DynamicFilter.Binder.Net -Version 2.5.9
<PackageReference Include="romaklayt.DynamicFilter.Binder.Net" Version="2.5.9" />
paket add romaklayt.DynamicFilter.Binder.Net --version 2.5.9
#r "nuget: romaklayt.DynamicFilter.Binder.Net, 2.5.9"
// Install romaklayt.DynamicFilter.Binder.Net as a Cake Addin #addin nuget:?package=romaklayt.DynamicFilter.Binder.Net&version=2.5.9 // Install romaklayt.DynamicFilter.Binder.Net as a Cake Tool #tool nuget:?package=romaklayt.DynamicFilter.Binder.Net&version=2.5.9
romaklayt.DynamicFilter
Simple filter for .net WebApi that enables your endpoint to query your requests by url.
It provides ways to query, order and page your webapi and mvc.
.Net Core and .Net
First, download the packages into your project from nuget
nuget install romaklayt.DynamicFilter.Extensions.EntityFrameworkCore
nuget install romaklayt.DynamicFilter.Binder.Net
and, if you need, add to your ConfigureServices Startup.cs class for register value provider (JSON) for body JSON POST request support (providers for form-data, x-www-form-urlencoded work them by default)
services.AddControllers(options => options.ValueProviderFactories.Add(new JsonBodyValueProviderFactory()));
If you need to use DynamicFilter with IAsyncEnumerable or IAsyncQueryable use the package
nuget install romaklayt.DynamicFilter.Extensions.Async
After downloaded, go to your webapi and create an get or post endpoint receiving IDynamicComplex
as
parameter.
[HttpGet]
public Task<List<User>> Get([FromQuery] DynamicComplex filter)
Now you can query your endpoint with the DynamicFilter properties. Check "tests" folder on the Api projects for examples.
[HttpGet]
public Task<List<User>> Get([FromQuery] DynamicComplex filter)
{
return users.Apply(filter).ToList();
}
DynamicFilter.Parser will transform your URI Queries into .Net Expressions. That way, you can use these expressions to filter your values into your database repository.
Simple Filter
You can use a DynamicComplexModel model for filtering. A DynamicFilterModel model without additional properties is also available.
public Task<List<User>> Get([FromQuery] DynamicComplex filter) #or DynamicFilterModel
{
return users.Apply(filter).ToList(); #ApplyFilter for DynamicFilterModel
}
Example Uri:
GET http://url?filter=name==Bruno
Expression generated by Uri:
x => x.Name == "Bruno"
Filters are also supported for nested collections.
GET http://url?filter=roles.name==admin
Your request will be converted to:
users.Where(x => x.Roles.Any(y => y.Name == "admin"))
If the standard behavior for arrays and lists using the Any method does not suit you, you can add the '=' sign after the comparison operator, after which the system will use the All method for arrays:
GET http://url?filter=roles.name===admin
Your request will be converted to:
users.Where(x => x.Roles.All(y => y.Name == "admin"))
The parser supports the count property for the collection, you can use it as a regular collection property:
GET http://url?filter=roles.count==1
If you need to filter values by default for the value type, use \default:
GET http://url?filter=roles.name==\default
Complex Filter
Boolean operators &&(and) and ||(or) are supported.
Example Uri:
GET http://url?filter=name==Bruno&&lastname@=r&&age>=27
Since version 2.0 more complex filters are available. You can use brackets to create more complex expressions.
GET http://url?filter=(name==Bruno&&lastname@=r)||(age>=27)
GET http://url?filter=(name==Bruno&&lastname@=r)||(age>=27&&name==Bruno)
You can nest multiple parentheses to create complex expressions.
GET http://url?filter=((name==Bruno&&lastname@=r)||(age>=27))&&roles.name==Admin
Attention!
For correct parsing of the filter, when using brackets, enclose all logical elements in brackets, for example:
Not correct
GET http://url?filter=((name==Bruno&&lastname@=r)||age>=27)&&roles.name==Admin
Correct (age>=27 in brackets)
GET http://url?filter=((name==Bruno&&lastname@=r)||(age>=27))&&roles.name==Admin
Nested Filer
Example Uri:
GET http://url?filter=address.number==23
Expression generated by Uri:
x => x.Address.Number == 23
Ordering
You can also order your queries via DynamicFilter. You simply need to add an order parameter on your query, where you specify the property you'll use for order.
GET http://url?filter=name==Bruno&order=name
Default order type is Ascending. You can adding a -
before the name switches to sorting descendingly..
GET http://url?filter=name==Bruno&order=name
GET http://url?filter=name==Bruno&order=-name
To sort by multiple properties:
GET http://url?filter=name==Bruno&order=name,firstname
GET http://url?filter=name==Bruno&order=-name,-firstname
If you do not specify the sort type, asc is used by default.
On your DynamicFilter object received on the endpoint, you'll get the orderType as an Enum, this way you can order by the type specified on enum.
public Task<List<User>> Get([FromQuery] DynamicComplex filter)
{
return users.Apply(filter).ToList();
}
Pagging
GET http://url?filter=name@=*b&order=name&page=1&pagesize=10
In romaklayt.DynamicFilter.Extensions.* there is a method of expanding the ToPageModel which returns PageModel with info about page and your filtered data.
var page = users.ToPageModel(filterModel);
The PageModel is built on top of the List<T> so to add page information to the server response you need to add an AddPageInfoFilter which will write the page information to the headers.
services.AddControllers(options =>
{
options.Filters.Add(new PageInfoWriter());
});
If you no need page info, you simply needs to add the parameters page and pagesize on your get request.
result = result.ApplyFilter(filter); #page mode without additional info
If you specify the page number and size in the filter model, pagination is disabled when using ApplyFilter. You can also disable pagination by forcibly calling:
result = result.ApplyFilter(filter, false); #only filtering without pagination
Example:
[HttpGet("page")]
public async Task<PageModel<User>> GetPage([FromQuery] DynamicComplex filterModel)
{
return Data.Users.ToPageModel(filterModel);
}
Select
To select, you simply needs to add the parameter select with the properties you want to select from. It will render either an linq select and a plain string select.
GET http://url?select=name,age
If you select a nested property, from default, the properties from the root model will be ignored, to select all the root properties, use the word root.
GET http://url?select=address.zip,root #select Address.Zip and all root properties
If you need to select properties from only one model (the GetById method, for example), you can also use the method ** ApplyFilter**.
[HttpGet("{id}")]
public async Task<object> GetById([FromQuery] DynamicSelect dynamicSelectModel, Guid id)
{
return await Data.Users.ApplySelect(dynamicSelectModel).DynamicFirstOfDefault("Id", id);
}
Filter operator support
Operator | Meaning |
---|---|
== |
Equals |
> |
Greater than |
< |
Less than |
>= |
Greater than or equal to |
<= |
Less than or equal to |
@= |
Contains |
_= |
Starts with |
_-= |
Ends with |
@=* |
Case-insensitive string Contains |
_=* |
Case-insensitive string Starts with |
_-=* |
Case-insensitive string Ends with |
==* |
Case-insensitive string Equals |
All operators support negation, you need to put "!" before the operator (e.g. !== for Equals)
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net8.0
- romaklayt.DynamicFilter.Common (>= 2.5.9)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2.5.9 | 250 | 9/24/2024 |
2.5.8 | 470 | 8/11/2024 |
2.5.7 | 694 | 4/27/2024 |
2.5.6 | 125 | 4/18/2024 |
2.5.5 | 111 | 4/10/2024 |
2.5.4 | 111 | 4/2/2024 |
2.5.3 | 117 | 4/1/2024 |
2.5.2 | 132 | 3/8/2024 |
2.5.1 | 119 | 3/3/2024 |
2.5.0 | 179 | 1/6/2024 |
2.4.5 | 187 | 8/14/2023 |
2.4.4 | 162 | 8/14/2023 |
2.4.3 | 197 | 6/18/2023 |
2.4.2 | 165 | 6/18/2023 |
2.4.1 | 179 | 6/7/2023 |
2.4.0 | 163 | 6/5/2023 |
2.3.5 | 164 | 6/2/2023 |
2.3.4 | 210 | 4/19/2023 |
2.3.3 | 188 | 4/18/2023 |
2.3.2 | 189 | 4/16/2023 |
2.3.1 | 205 | 4/9/2023 |
2.3.0 | 200 | 4/9/2023 |
2.2.1 | 203 | 4/8/2023 |
2.2.0 | 211 | 4/8/2023 |
2.2.0-tags-2-2-0-beta-1.1 | 79 | 4/8/2023 |
2.1.2 | 395 | 11/4/2022 |
2.1.1 | 371 | 11/4/2022 |
2.1.0 | 396 | 9/24/2022 |
2.1.0-beta.1 | 102 | 9/9/2022 |
2.0.0 | 432 | 9/2/2022 |
2.0.0-beta.3 | 123 | 7/28/2022 |
2.0.0-beta.2 | 104 | 7/26/2022 |
2.0.0-beta.1 | 113 | 7/19/2022 |
1.9.3 | 494 | 4/21/2022 |
1.9.2 | 467 | 4/10/2022 |
1.9.1 | 462 | 4/6/2022 |
1.9.0 | 449 | 4/5/2022 |
1.8.1 | 454 | 3/27/2022 |
1.8.0 | 450 | 3/7/2022 |
1.7.12 | 393 | 10/5/2022 |
1.7.11 | 524 | 2/8/2022 |
1.7.10 | 450 | 2/8/2022 |
1.7.9 | 469 | 1/11/2022 |
1.7.8 | 471 | 1/11/2022 |
1.7.7 | 458 | 1/11/2022 |
1.7.6 | 469 | 1/11/2022 |
1.7.5 | 460 | 1/10/2022 |
1.7.4 | 309 | 12/26/2021 |
1.7.3 | 320 | 12/17/2021 |
1.7.2 | 314 | 12/12/2021 |
1.7.1 | 333 | 12/3/2021 |
1.7.0 | 341 | 11/14/2021 |
1.6.5 | 406 | 11/6/2021 |
1.6.4 | 387 | 10/26/2021 |
1.6.3 | 352 | 10/12/2021 |
1.6.2 | 393 | 10/12/2021 |
1.6.1 | 355 | 10/12/2021 |
1.6.0 | 352 | 10/11/2021 |
1.5.5 | 350 | 10/6/2021 |
1.5.4 | 359 | 10/6/2021 |
1.5.3 | 383 | 9/27/2021 |
1.5.2 | 331 | 9/27/2021 |
1.5.1 | 361 | 9/27/2021 |
1.5.0 | 369 | 9/27/2021 |
1.4.1 | 365 | 9/24/2021 |
1.4.0 | 406 | 9/24/2021 |
1.3.1 | 402 | 9/22/2021 |
1.3.0 | 359 | 9/20/2021 |
1.2.0 | 376 | 9/17/2021 |
1.1.4 | 393 | 9/17/2021 |
1.1.3 | 383 | 9/17/2021 |
1.1.2 | 370 | 9/17/2021 |
1.1.1 | 354 | 9/16/2021 |
1.1.0 | 383 | 9/13/2021 |
1.0.2 | 436 | 9/10/2021 |
1.0.1 | 406 | 9/10/2021 |
1.0.0 | 393 | 9/10/2021 |