Cocoar.FluentJson 0.2.0-alpha.7

This is a prerelease version of Cocoar.FluentJson.
dotnet add package Cocoar.FluentJson --version 0.2.0-alpha.7
                    
NuGet\Install-Package Cocoar.FluentJson -Version 0.2.0-alpha.7
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Cocoar.FluentJson" Version="0.2.0-alpha.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Cocoar.FluentJson" Version="0.2.0-alpha.7" />
                    
Directory.Packages.props
<PackageReference Include="Cocoar.FluentJson" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Cocoar.FluentJson --version 0.2.0-alpha.7
                    
#r "nuget: Cocoar.FluentJson, 0.2.0-alpha.7"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Cocoar.FluentJson@0.2.0-alpha.7
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Cocoar.FluentJson&version=0.2.0-alpha.7&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Cocoar.FluentJson&version=0.2.0-alpha.7&prerelease
                    
Install as a Cake Tool

Cocoar.FluentJson

License NuGet CI

Cocoar.FluentJson is a C# source generator + runtime library that automatically generates JsonConverter<T> implementations for System.Text.Json based on fluent configuration rules. It lets you define custom JSON serialization and deserialization behavior without manually writing converter code.

Contributions are welcome! Feel free to open issues or pull requests for improvements or new features.


Features

  • Source Generation: Automatically generates JsonConverter<T> classes at compile-time
  • Fluent Configuration: Define JSON rules using a clean, fluent API
  • Property Control: Rename, ignore, or apply custom logic to individual properties
  • Custom Converters: Use separate read and write converters for properties
  • Inline Logic: Define custom serialization logic directly in configuration
  • Compile-time Validation: Catch configuration errors during build

Installation

Install the NuGet package:

dotnet add package Cocoar.FluentJson

Note: The single NuGet package contains:

  • Runtime assembly (Cocoar.FluentJson.dll) for net8.0 & net9.0
  • Shared contracts & source generator delivered via analyzer (analyzers/dotnet/cs) No extra setup beyond installing the package.

How It Works

  1. Create a partial class that implements IFluentJsonConverter<T>
  2. Define fluent rules in the CreateFluentRules method
  3. The source generator automatically creates a complete JsonConverter<T> implementation
  4. Register the converter with JsonSerializerOptions

Getting Started

1. Define Your Model

Create your data model that needs custom JSON serialization:

public class NeededServiceConfig
{
    public int LocalPort { get; set; }
    public bool Direct { get; set; }
    public string Destination { get; set; }
    public string ServiceName { get; set; }
}

2. Implement IFluentJsonConverter<T>

Create a partial class that implements the interface:

public partial class NeededConfigConverter : IFluentJsonConverter<NeededServiceConfig>
{
    public void CreateFluentRules(IFluentConverterRulesBuilder<NeededServiceConfig> rules)
    {
        rules
            .ForProperty(x => x.Destination, x => x.Read((ref Utf8JsonReader r) =>
                r.TokenType == JsonTokenType.Number ? $"localhost:{r.GetInt32()}" : r.GetString()!))
            .ForProperty(x => x.Direct, x => x.Read((ref Utf8JsonReader reader) => 
                reader.TokenType == JsonTokenType.String
                    ? bool.Parse(reader.GetString()!)
                    : reader.GetBoolean()))
            .Ignore(x => x.ServiceName);
    }
}

3. Register and Use the Converter

var options = new JsonSerializerOptions
{
    Converters = { new NeededConfigConverter() }
};

var json = """{"LocalPort": 1434, "Destination": 1433, "Direct": "true"}""";
var config = JsonSerializer.Deserialize<NeededServiceConfig>(json, options);
// config.Destination = "localhost:1433"
// config.Direct = true
// config.ServiceName = null (ignored)

API Reference

IFluentConverterRulesBuilder<T>

The fluent builder provides methods to configure JSON serialization rules:

ForProperty(propertyExpression, configure)

Configure rules for a specific property using the property configurator.

Ignore(propertyExpression)

Skip a property during both serialization and deserialization.

IPropertyConfigurator<T, TProperty>

Available configuration methods for individual properties:

Rename(string newName)

Change the JSON property name.

Ignore()

Skip this property (alternative to Ignore() on the builder).

UseReadConverter<TConverter>()

Use a custom JsonConverter<TProperty> only for reading (deserialization).

UseWriteConverter<TConverter>()

Use a custom JsonConverter<TProperty> only for writing (serialization).

Read(ReadDelegate<TProperty> inlineRead)

Define inline deserialization logic using a delegate.

Write(Action<Utf8JsonWriter, TProperty> inlineWrite)

Define inline serialization logic using an action.

Example Configurations

rules
    .ForProperty(x => x.Id, x => x.Rename("identifier"))
    .ForProperty(x => x.Value, x => x.UseReadConverter<CustomStringConverter>())
    .ForProperty(x => x.Data, x => x.Read((ref Utf8JsonReader reader) => 
        reader.TokenType == JsonTokenType.Number 
            ? reader.GetInt32().ToString() 
            : reader.GetString()))
    .Ignore(x => x.InternalProperty);

Generated Code

The source generator creates a partial implementation of your converter class that extends JsonConverter<T>. For example:

// Generated code (conceptual - actual implementation may vary)
public partial class NeededConfigConverter : JsonConverter<NeededServiceConfig>
{
    public override NeededServiceConfig Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // Generated switch statement handling each property
        // with custom logic, converters, and default behavior
    }

    public override void Write(Utf8JsonWriter writer, NeededServiceConfig value, JsonSerializerOptions options)
    {
        // Generated serialization logic respecting
        // renames, ignores, and custom converters
    }
    
    // Generated helper methods for inline logic
    private string Read_Destination(ref Utf8JsonReader reader) { /* custom logic */ }
}

Known Limitations

⚠️ Current limitations that may be addressed in future versions:

  1. Complex Lambda Expressions: Inline Read() and Write() methods support basic lambda expressions, but complex multi-statement blocks may not parse correctly.

  2. Write Method Parameter Parsing: The inline Write() lambda parameter detection may have edge cases with complex parameter patterns.

  3. Converter Validation: While the source generator validates that converters are not abstract, additional validation for proper inheritance could be improved.

  4. Error Reporting: Diagnostic error messages could be more detailed and provide better guidance for fixing configuration issues.

  5. Method Chaining Limitations: Very deep method chaining in configuration might not be fully supported by the syntax parser.

  6. Generic Type Constraints: Custom converters with complex generic constraints may not be properly validated at compile time.

Technical Details

  • Runtime Target Frameworks: net8.0, net9.0
  • Generator & Shared Contracts: netstandard2.0 (broad IDE / compiler compatibility)
  • Key Dependencies:
    • Microsoft.CodeAnalysis.CSharp 4.12.0 (analyzer/generator only)
    • System.Text.Json 9.0.0
  • Package Layout:
    • lib/net8.0|net9.0: runtime + shared DLL
    • analyzers/dotnet/cs: generator + shared DLL (for compile-time)
  • Debugging: Attach to a build with generator debug launch profile (see Properties/launchSettings.json).

Why Cocoar.FluentJson?

Cocoar.FluentJson saves time and effort by:

  • Centralizing JSON rules.
  • Reducing boilerplate code.
  • Providing type-safe compile-time validation.

It’s especially useful in projects with complex models and custom serialization requirements.


Contributing

Contributions are welcome! Feel free to open issues or pull requests for improvements or new features.


License

This project is licensed under the MIT License.


Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.
  • net9.0

    • No dependencies.

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
0.2.0-alpha.7 161 9/24/2025
0.2.0-alpha.6 151 9/24/2025

Initial beta release providing fluent JsonSerializerOptions builder and source generator for custom converters.