SystemTextJson.FluentApi 1.0.0-preview.1.0.3

This is a prerelease version of SystemTextJson.FluentApi.
There is a newer version of this package available.
See the version list below for details.
dotnet add package SystemTextJson.FluentApi --version 1.0.0-preview.1.0.3                
NuGet\Install-Package SystemTextJson.FluentApi -Version 1.0.0-preview.1.0.3                
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="SystemTextJson.FluentApi" Version="1.0.0-preview.1.0.3" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add SystemTextJson.FluentApi --version 1.0.0-preview.1.0.3                
#r "nuget: SystemTextJson.FluentApi, 1.0.0-preview.1.0.3"                
#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.
// Install SystemTextJson.FluentApi as a Cake Addin
#addin nuget:?package=SystemTextJson.FluentApi&version=1.0.0-preview.1.0.3&prerelease

// Install SystemTextJson.FluentApi as a Cake Tool
#tool nuget:?package=SystemTextJson.FluentApi&version=1.0.0-preview.1.0.3&prerelease                

NuGet WARNING: this package is under active development so the api may change at any time.

SystemTextJson.FluentApi

SystemTextJson.FluentApi is a fluent configuration library for System.Text.Json that allows developers to configure serialization uses strongly typed fluent interface and lambda expression.

Documentation

All api usually repeats attributes from System.Text.Json.Serialization and set corresponding property in JsonPropertyInfo or JsonTypeInfo. Configuration based on IJsonTypeInfoResolver so developers can configure reflection based TypeInfoResolver and source generator JsonSerializerContext.

Quick start

To use FluentApi need to configure JsonSerializerOptions instance via JsonModelBuilder and pass it to serializer.

var options = new JsonSerializerOptions() { WriteIndented = true };
options.ConfigureDefaultTypeResolver(p =>
p.Entity<Person>()
.Property(p => p.LastName).HasName("surname")
.Property(p => p.FirstName).IsIgnored()
.VirtualProperty("FullName", p => $"{p.FirstName} {p.LastName}")
.Property(p => p.Age).HasHumberHandling(JsonNumberHandling.WriteAsString));

var person = new Person() { FirstName = "First name", LastName = "Last name", Age = 12 };
var json = JsonSerializer.Serialize(person, options);

Console.WriteLine(json);

This example produce this JSON

{
  "surname": "Last name",
  "Age": "12",
  "FullName": "First name Last name"
}

Polymorphism serialization

STJ has build in support polymorphic serialization, but user have to annotate base class with JsonDerivedTypeAttribute with all derived types. In fluent API you can configure each derived type manually or find all derived types in runtime.

builder.Entity<Root>()
.HasDerivedType<Derived1>(nameof(Derived1))
.HasDerivedType<Derived2>(nameof(Derived2))
.HasDerivedType<Root>(nameof(Root))
// or
builder.Entity<Root>().HasDerivedTypesFromAssembly(Assembly.GetExecutingAssembly(), t => t.Name)

var testObject = new Root[] 
{
    new Derived1() { Derived1Property = "derived" },
    new Derived2() { Derived2Property = "derived2" },
    new Root(){ RootProperty = "root"}
};


public class Root
{
    public string? RootProperty { get; set; }
}

public class Derived1 : Root
{
    public string? Derived1Property { get; set; }
}

public class Derived2 : Root
{
    public string? Derived2Property { get; set; }
}

Serialization of testObject collection will produce:

[
   {
      "$type":"Derived1",
      "Derived1Property":"derived",
      "RootProperty":null
   },
   {
      "$type":"Derived2",
      "Derived2Property":"derived2",
      "RootProperty":null
   },
   {
      "$type":"Root",
      "RootProperty":"root"
   }
]

With $type discriminator serializer are able to deserialize this collection. Another approach to serialization is use actual type from object instance, instead of property type. To achieve this behavior serializer can threat specific type as object. Fluent Api has two way for this - configure behavior for specific property with PropertyBuilder.SerializeAsObject or for specific type with JsonSerializerOptionsExtensions.SerializeAsObject.

builder.Entity<AsObjectTestClass>().Property(p => p.Data).SerializeAsObject();
// or 
options.SerializeAsObject<Root>();

var testObject = new AsObjectTestClass { Data = new Derived() { Property = "Prop" } };

public class AsObjectTestClass
{
    public Root? Data { get; set; }
}

public class Root { }

public class Derived : Root
{
    public string? Property { get; set; }
}

Serialization of testObject will produce:

{
   "Data":{
      "Property":"Prop"
   }
}

But in this case only serialization is available because JSON does not contain type discriminator and JsonException will be thrown on deserialization.

Nullable reference type support

STJ has build in support of required properties, but it just check, that value exists in JSON on deserialization and does not prevent setting null to none nullable properties. Fluent Api can configure JsonSerializerOptions to respect NRT annotations on fields and properties. Internally it uses JsonPropertyInfo.Set property and reduces deserialization performance.

builder.RespectNullableReferenceType();

JsonSerializer.Deserialize<TestClass>("""{"Property": null}""", _options); // this throws JsonException
JsonAsserts.AssertObject(new TestClass(), "{}", _options); // BUT this is not because Property is not requred.

public class TestClass
{
    public string Property { get; set; }
}

Virtual properties

Fluent Api can define virtual properties, that does not match to any real property in object.

builder.Entity<Person>()
.Property(p => p.LastName).IsIgnored()
.Property(p => p.FirstName).IsIgnored()
.VirtualProperty("FullName", p => $"{p.FirstName} {p.LastName}")

var testObject = new Person() { FirstName = "First name", LastName = "Last name" };

class Person
{
    public string? FirstName { get; set; }

    public string? LastName { get; set; }
}

Serialization of testObject collection will produce:

{
    "FullName": "First name Last name"
}
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  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 is compatible.  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 was computed.  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. 
.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 is compatible.  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.

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
1.0.1 138 1/25/2024
1.0.0 183 11/17/2023
1.0.0-preview.1.0.4 70 11/8/2023
1.0.0-preview.1.0.3 70 11/5/2023
1.0.0-preview.1.0.2 67 11/5/2023
1.0.0-preview.1.0.1 70 11/4/2023