SpanJson Documentation

repository·master·Indexed 19 days ago

https://github.com/tornhoof/spanjson

A high-performance JSON serialization and deserialization library for .NET designed for efficiency with Span<T> and ArrayPool. It supports UTF-8 and UTF-16 formats, provides synchronous and asynchronous APIs, and includes custom formatter and resolver support. The library also offers integration for ASP.NET Core 6.0+ via the SpanJson.AspNetCore.Formatter package.

Tokens
2.4K
Snippets
7
Records
7
Agent score
16%

What's inside SpanJson

  1. Configure JSON member mapping and behavior with attributes

    master

    You can control how SpanJson handles specific members of your classes using several attributes:

    • [DataMember(Name="MemberName")]: Sets a specific name for the field in the JSON output.
    • [IgnoreDataMember]: Prevents a specific member from being serialized or deserialized.
    • [JsonConstructor]: Specifies which constructor to use during deserialization. If parameter names match member names (case-insensitive), they are mapped automatically. You can also use [JsonConstructor(nameof(Member1), nameof(Member2))] to explicitly map constructor parameters to specific members.
    • [JsonCustomSerializer(typeof(FormatterType))]: Directs SpanJson to use a specific ICustomJsonFormatter<T> for a member or type instead of the default formatter.
    • [JsonExtensionData]: When applied to an IDictionary<string, object>, all unknown properties during deserialization are added to this dictionary. During serialization, all entries in the dictionary are written as additional properties of the object.
    public class ExtensionTest
    {
        public string Key;
        public string Value;
    
        [JsonExtensionData]
        public IDictionary<string, object> AdditionalValues { get; set; }
    }
    
    public class Input
    {
        [DataMember(Name="custom_name")]
        public string Text { get; set; }
    
        [IgnoreDataMember]
        public string Secret { get; set; }
    }
  2. Enable SpanJson as the ASP.NET Core Formatter

    master

    To use SpanJson as the default JSON formatter in ASP.NET Core 6.0+, install the SpanJson.AspNetCore.Formatter NuGet package. You can enable it by calling one of the following extension methods on your AddMvc() configuration in ConfigureServices:

    • AddSpanJson(): Uses the AspNetCoreDefaultResolver which provides behavior similar to JSON.NET (includes IncludeNull, CamelCase, and Integer Enums).
    • AddSpanJsonCustom<TResolver>(): Allows you to specify a custom resolver type.

    Warning: Enabling SpanJson clears the existing Formatter list. If your application relies on other formatters (such as JSON Patch or XML), you must manually re-add them after calling these methods.

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().AddSpanJson();
    }
  3. Use SpanJson for JSON serialization and deserialization

    master

    SpanJson provides high-performance serialization and deserialization for various .NET types. It supports both UTF-16 (strings) and UTF-8 (byte arrays/streams) formats. You can use the JsonSerializer.Generic API for type-safe operations or JsonSerializer.NonGeneric when working with typeof(T).

    Synchronous API

    • UTF-16: Use JsonSerializer.Generic.Utf16 or JsonSerializer.NonGeneric.Utf16.
    • UTF-8: Use JsonSerializer.Generic.Utf8 or JsonSerializer.NonGeneric.Utf8.

    Asynchronous API

    • Supports ValueTask and ValueTask<T> for non-blocking I/O with TextWriter, TextReader, or Stream.

    Memory Management

    Methods like SerializeToArrayPool return an ArraySegment from the ArrayPool. You are responsible for returning the segment to the pool after use.

    // Synchronous UTF-16
    var result = JsonSerializer.Generic.Utf16.Serialize(input);
    var result = JsonSerializer.Generic.Utf16.Deserialize<Input>(input);
    
    // Synchronous UTF-8
    var result = JsonSerializer.Generic.Utf8.Serialize(input);
    var result = JsonSerializer.Generic.Utf8.Deserialize<Input>(input);
    
    // ArrayPool (MUST return the segment manually)
    var result = JsonSerializer.Generic.Utf8.SerializeToArrayPool(input);
    
    // Asynchronous
    await JsonSerializer.Generic.Utf8.SerializeAsync(input, stream, cancellationToken);
    await JsonSerializer.Generic.Utf8.DeserializeAsync<Input>(input, stream, cancellationToken);
  4. Implement a Custom Resolver for SpanJson

    master

    Because SpanJson options are provided via concrete classes, you cannot easily request every possible combination through pre-built types. To use a specific combination of SpanJsonOptions, you must implement your own custom resolver by inheriting from ResolverBase<TSymbol, TResolver>.

    Example implementation of a custom resolver with specific options for null handling, naming conventions, enums, and byte arrays:

    public sealed class CustomResolver<TSymbol> : ResolverBase<TSymbol, CustomResolver<TSymbol>> where TSymbol : struct
    {
        public CustomResolver() : base(new SpanJsonOptions
        {
            NullOption = NullOptions.ExcludeNulls,
            NamingConvention = NamingConventions.CamelCase,
            EnumOption = EnumOptions.Integer,
            ByteArrayOptions = ByteArrayOptions.Base64
        })
        {
        }
    }
  5. Implement a custom JSON formatter with ICustomJsonFormatter

    master

    To implement custom logic for a specific type (e.g., converting a long to a string in JSON), implement the ICustomJsonFormatter<T> interface. You must provide implementations for both UTF-8 (byte) and UTF-16 (char) versions of Serialize and Deserialize to ensure full compatibility.

    When using [JsonCustomSerializer(typeof(Formatter), "argument")], the string argument is assigned to the Arguments property of your formatter instance.

    public sealed class LongAsStringFormatter : ICustomJsonFormatter<long>
    {
        public object Arguments { get; set; }
    
        // UTF-16 implementation
        public void Serialize(ref JsonWriter<char> writer, long value) => 
            StringUtf16Formatter.Default.Serialize(ref writer, value.ToString(CultureInfo.InvariantCulture));
    
        public long Deserialize(ref JsonReader<char> reader) => 
            long.Parse(StringUtf16Formatter.Default.Deserialize(ref reader));
    
        // UTF-8 implementation
        public void Serialize(ref JsonWriter<byte> writer, long value) => 
            StringUtf8Formatter.Default.Serialize(ref writer, value.ToString(CultureInfo.InvariantCulture));
    
        public long Deserialize(ref JsonReader<byte> reader) => 
            long.Parse(StringUtf8Formatter.Default.Deserialize(ref reader));
    }
  6. Format JSON with Pretty Printing or Minification

    master

    SpanJson provides utility classes to transform existing serialized JSON strings:

    • JsonSerializer.PrettyPrinter.Print(serialized): Re-writes the JSON with spaces and line breaks for readability.
    • JsonSerializer.Minifier.Minify(serialized): Re-writes the JSON without spaces or line breaks to reduce size.
    var pretty = JsonSerializer.PrettyPrinter.Print(serialized);
    var minified = JsonSerializer.Minifier.Minify(serialized);
  7. Use different Resolvers to control null handling and casing

    master

    You can control how null values and property casing are handled by using different Resolvers via the generic overloads of the serialization methods.

    Available Resolvers:

    • ExcludeNullsCamelCaseResolver
    • ExcludeNullsOriginalCaseResolver (Default)
    • IncludeNullsCamelCaseResolver
    • IncludeNullsOriginalCaseResolver
    // Example of using a specific resolver
    var serialized = JsonSerializer.NonGeneric.Utf16.Serialize<Input, IncludeNullsCamelCaseResolver<char>>(input);