FieldTypedJsonConverter 1.0.1
dotnet add package FieldTypedJsonConverter --version 1.0.1
NuGet\Install-Package FieldTypedJsonConverter -Version 1.0.1
<PackageReference Include="FieldTypedJsonConverter" Version="1.0.1" />
<PackageVersion Include="FieldTypedJsonConverter" Version="1.0.1" />
<PackageReference Include="FieldTypedJsonConverter" />
paket add FieldTypedJsonConverter --version 1.0.1
#r "nuget: FieldTypedJsonConverter, 1.0.1"
#:package FieldTypedJsonConverter@1.0.1
#addin nuget:?package=FieldTypedJsonConverter&version=1.0.1
#tool nuget:?package=FieldTypedJsonConverter&version=1.0.1
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
- Create an abstract base class
- Derive types from it
- Call
.Mapto 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 | Versions 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. |
-
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.