using Microsoft.AspNetCore.WebUtilities;
using System.Collections.Generic;
using Newtonsoft.Json.Serialization;
public static void Main()
ICollection<Filter> filters =
TargetPropertyType = FilterTargetPropertyType.String,
FilterDisplayName = "Part",
FilterTargetProperty = "PartNo",
FilterValue = "=1109-840-835"
TargetPropertyType = FilterTargetPropertyType.String,
FilterDisplayName = "Site",
FilterTargetProperty = "Contract",
JsonSerializerSettings serializerSettings = new ()
TypeNameHandling = TypeNameHandling.Objects,
SerializationBinder = new FilterSerializerBinder()
string json = filters.ToJSON(serializerSettings);
Console.WriteLine("------------------------------------");
string base64 = filters.ToBase64FromJSON(serializerSettings);
Console.WriteLine(base64);
Console.WriteLine("------------------------------------");
string jsonFromBase64 = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(base64));
Console.WriteLine(jsonFromBase64);
Console.WriteLine("------------------------------------");
ICollection<Filter> decoded = [ .. JsonConvert.DeserializeObject<IEnumerable<Filter>>(jsonFromBase64, serializerSettings)];
foreach (Filter f in decoded)
Console.WriteLine(f.ToString());
public static class CollectionExtensions
public static string ToJSON<TSource>(this ICollection<TSource> source, JsonSerializerSettings? jsonSerializerSettings = default) =>
jsonSerializerSettings is not null ? JsonConvert.SerializeObject(source, jsonSerializerSettings) : JsonConvert.SerializeObject(source);
public static string ToBase64FromJSON<TSource>(this ICollection<TSource> source, JsonSerializerSettings? jsonSerializerSettings = default) => WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(source.ToJSON(jsonSerializerSettings)));
public class FilterSerializerBinder : ISerializationBinder
public List<Type> Types { get; set; } = [typeof(Filter), typeof(TextFilter)];
public void BindToName(Type serializedType, out string? assemblyName, out string? typeName)
assemblyName = Assembly.GetAssembly(serializedType)?.FullName;
typeName = serializedType.Name;
public Type BindToType(string? assemblyName, string typeName)
return Types.Single(t => t.Name == typeName);
public abstract record Filter
public abstract bool HasValue { get; }
public virtual bool IsVisible { get; set; } = false;
public required virtual string FilterDisplayName { get; init; }
public required virtual string FilterTargetProperty { get; init; }
public sealed record class TextFilter : Filter
public override bool HasValue => IsVisible && !string.IsNullOrWhiteSpace(FilterValue);
public string FilterValue
_FilterValue = value ?? string.Empty;
private string _FilterValue = string.Empty;
public required FilterTargetPropertyType TargetPropertyType { get; init; }
public enum FilterTargetPropertyType