Panner 3.0.0
dotnet add package Panner --version 3.0.0
NuGet\Install-Package Panner -Version 3.0.0
<PackageReference Include="Panner" Version="3.0.0" />
<PackageVersion Include="Panner" Version="3.0.0" />
<PackageReference Include="Panner" />
paket add Panner --version 3.0.0
#r "nuget: Panner, 3.0.0"
#addin nuget:?package=Panner&version=3.0.0
#tool nuget:?package=Panner&version=3.0.0
ASP.NET Core WebAPI? You should start with Panner.AspNetCore!
Panner

Clean, customizable & extensible framework for the configuration, parsing and application of sorts and filters from a CSV.
Basic Usage - Sample
a. Configuration
Setting up your context to define your entities and rules.
var builder = new PContext();
// Entity wide configuration (Option 1)
builder.Entity<Post>()
.AllPropertiesAreSortableByName();
.AllPropertiesAreFilterableByName();
// A more granular approach (Option 2)
builder.Entity<Post>()
.Property(x => x.Id, o => o
.IsSortableByName()
.IsFilterableByName()
).Property(x => x.Title, o => o
.IsSortableByName()
.IsFilterableByName()
).Property(x => x.CreatedOn, o => o
.IsSortableAs("Creation")
.IsFilterableAs("Creation")
);
// And then we build our context.
IPContext context = builder.Build();
// Ta-daah! Now we have a context!
b. Parsing
Feeding Panner's context our CSV inputs and obtaining sort/filter particles
Sorts
var csvSort = "-Title, Id"; // Example
if (!context.TryParseCsv(
input: csvSort,
out IEnumerable<ISortParticle<TEntity>> sortParticles
)){
// Parsing failed
return;
}
// Ta-daah! Now we have sort particles!
Filters
var csvFilter = "Id<666, Id>13"; // Example
if (!context.TryParseCsv(
input: csvFilter,
out IEnumerable<IFilterParticle<TEntity>> filterParticles
)){
// Parsing failed
return;
}
// Ta-daah! Now we have filter particles!
c. Application
Using Panner's extension methods to apply our particles to any IEnumerable
, IQueryable
, DbSet
, etc..
var pannedQueryable = posts
.Apply(filterParticles)
.Apply(sortParticles);
// Ta-daah! Now we have a filtered and sorted IQueryable!
Advanced Usage - Samples
<details> <summary> <b>Custom sort for a specific entity</b><br/> Ability to sort our fake entity <code>Post</code> by "popularity", an arbritary concept and not a property of the entity.<br/> Leveraging <code>ISortParticle</code>, <code>ISortParticleGenerator</code> and extending <code>PEntityBuilder</code>. </summary> <p>
Particle - SortPostByPopularityParticle.cs
public class SortPostByPopularityParticle : ISortParticle<Post> // Panner's interface
{
readonly bool Descending;
public SortPostByPopularityParticle(bool descending)
{
this.Descending = descending;
}
public IOrderedQueryable<Post> ApplyTo(IOrderedQueryable<Post> source)
{
// Here's how the sorting is done when the particle is applied.
if (this.Descending)
return source
.ThenByDescending(x => x.AmtLikes)
.ThenByDescending(x => x.AmtComments);
else
return source
.ThenBy(x => x.AmtLikes)
.ThenBy(x => x.AmtComments);
}
}
Particle Generator - SortPostsByPopularityParticleGenerator.cs
public class SortPostsByPopularityParticleGenerator : ISortParticleGenerator<Post> // Panner's interface
{
public bool TryGenerate(IPContext context, string input, out ISortParticle<Post> particle)
{
var descending = input.StartsWith('-');
var remaining = descending ? input.Substring(1) : input;
if (!remaining.Trim().Equals("Popularity", System.StringComparison.OrdinalIgnoreCase))
{
// Not the input we're interested in.
particle = null;
return false;
}
particle = new SortPostByPopularityParticle(descending);
return true;
}
}
PEntityBuilder Extension - PEntityBuilder.Post.IsSortableByPopularity.cs
public static partial class PEntityBuilderExtensions
{
/// <summary>Marks the entity as sortable by popularity.</summary>
public static PEntityBuilder<Post> IsSortableByPopularity(this PEntityBuilder<Post> builder)
{
builder.GetOrCreateGenerator<ISortParticle<Post>, SortPostsByPopularityParticleGenerator>();
return builder; // So we can chain calls!
}
}
Setting it all up in the context builder
builder.Entity<Post>()
.IsSortableByPopularity();
Frequently Asked Questions
Using different culture for filter value conversions?
You can change CurrentInfo.CurrentCulture
before calling context.TryParseCsv([...])
!
CurrentInfo.CultureInfo = new CultureInfo("es"); //So simple...!
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. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Panner:
Package | Downloads |
---|---|
Panner.AspNetCore
Sorting and filtering made easy for your ASP.NET Core project! Go from a CSV input to a filtered/sorted IQueryable with no effort. |
GitHub repositories
This package is not used by any popular GitHub repositories.