FieldTypedJsonConverter 1.0.1

dotnet add package FieldTypedJsonConverter --version 1.0.1
                    
NuGet\Install-Package FieldTypedJsonConverter -Version 1.0.1
                    
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="FieldTypedJsonConverter" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FieldTypedJsonConverter" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="FieldTypedJsonConverter" />
                    
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 FieldTypedJsonConverter --version 1.0.1
                    
#r "nuget: FieldTypedJsonConverter, 1.0.1"
                    
#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 FieldTypedJsonConverter@1.0.1
                    
#: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=FieldTypedJsonConverter&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=FieldTypedJsonConverter&version=1.0.1
                    
Install as a Cake Tool

FieldTypedJsonConverter

FieldTypedJsonConverter is a JsonConverter that allows for deserialization of objects based on a mapping from a field's value to a type.

Published on NuGet as FieldTypedJsonConverter

The Basic Steps

  1. Create an abstract base class
  2. Derive types from it
  3. Call .Map to map strings to types

Example

Create your classes. The MessageBase abstract class has a field MessageType.

abstract class MessageBase
{
    public string? MessageType { get; init; }
}

class PingMessage : MessageBase {}
class PongMessage : MessageBase {}

Create your converter. Map field values.

var converter = new FieldTypedJsonConverter<MessageBase>("MessageType");
converter.Map("ping", typeof(PingMessage));
converter.Map("pong", typeof(PongMessage));

Add the converter to your JsonSerializerOptions.

var options = new JsonSerializationOptions();
options.Converters.Add(converter);

Now deserialize incoming messages, for example an HTTP POST request body.

var msg = JsonSerializer.Deserialize<MessageBase>(json, options);

The object returned depends on the field value present in the json.

var pingMessage = JsonSerializer.Deserialize<MessageBase>("{\"MessageType\": \"ping\"}", options);
var pongMessage = JsonSerializer.Deserialize<MessageBase>("{\"MessageType\": \"pong\"}", options);

Console.WriteLine(pingMessage.GetType().Name);
// PRINTS "PingMessage"

Console.WriteLine(pongMessage.GetType().Name);
// PRINTS "PongMessage"

Fallback

If the field is missing, or the value wasn't mapped to a type, a NotSupportedException will be thrown.

Alternatively, you can call SetFallbackType. If a fallback type is provided, the object will be deserialize as the fallback type instead of throwing the exception.

You could consider using [JsonExtensionData] on a field in the fallback type if you're still interested in the contents of the message.

Rules

The base class must be abstract.

All mapped types (including the fallback type) must derive from the base class.

Once the converter has been used, no changes to mappings are allowed.

Deserialization

Make sure to use the generic Deserialize call with the base type, in order to trigger the converter.

For example: JsonSerializer.Deserialize<MessageBase>(...

A typical usage scenario might look like:

var msg = JsonSerializer.Deserialize<MessageBase>(json, options);
switch (msg)
{
    case PingMessage ping: return await HandlePingAsync(ping);
    case PongMessage pong: return await HandlePongAsync(pong);
}

Serialization

Serialization is allowed, although this converter is typically used for deserialization scenarios.

Optionally, call DoFieldValueValidation if you want the field value to be checked according to the deserialization mapping. Make sure to use the generic Serialize call with the base type if you want this behavior, or else the converter will not be triggered.

AOT

In AOT scenarios, you may wish to derive your own converter and use it in a [JsonSourceGenerationOptions] attribute.

For example:

class PingPongConverter : FieldTypedJsonConverter<MessageBase>
{
    public PingPongConverter() : base("MessageType")
    {
        Map("Ping", typeof(PingMessage));
        Map("Pong", typeof(PongMessage));
    }
}

[JsonSourceGenerationOptions(Converters = [typeof(PingPongConverter)])]
[JsonSerializable(typeof(PingMessage))]
[JsonSerializable(typeof(PongMessage))]
partial class PingPongGenContext : JsonSerializerContext { }

Deserialization should still point to the abstract base class.

var msg = JsonSerializer.Deserialize("{\"MessageType\": \"ping\"}", PingPongGenContext.Default.MessageBase);

Console.WriteLine(msg.GetType().Name);
// PRINTS "PingMessage"
Product Compatible and additional computed target framework versions.
.NET 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • 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
1.0.1 192 10/13/2025
1.0.0 182 10/5/2025