I'm trying to do a polymorphic deserialization using System.Text.Json in net-8.0. Here is my schema.

[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] [JsonDerivedType(typeof(Manager), "Manager")] [JsonDerivedType(typeof(Developer), "Developer")] public class Employee { public string Type { get; set; } public string Name { get; set; } } public class Manager : Employee { public string Phone { get; set; } } public class Developer : Employee { public string Laptop { get; set; } } 

Here is my json.

[ { "type": "Manager", "name": "Bob", "phone": "9876543210" }, { "type": "Developer", "name": "Charlie", "laptop": "MacBook Pro" } ] 

and I'm doing this

var jsonFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Employees.json"); var employeesContent = File.ReadAllText(jsonFilePath); var jsonSerializerOptions = new JsonSerializerOptions(); jsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; var employees = JsonSerializer.Deserialize<List<Employee>>(employeesContent, jsonSerializerOptions); 

And the Type property inside Employee class is always null as shown in below screen shot.

Debug output

Please assist me on what I'm missing.

2 Replies 2

The type discriminator can't be an entity property as well. That's why the default is $type, not type. Right now you have an attribute named type that, according to the CamelCase options maps to the property Type and a discriminator also called type, that would map to the same attribute.

If you tried to serialize an array of Employees

Employee[] x=[new Manager{Name="Bob",Phone="9876543210"}, new Developer{Name="Charlie",Laptop="Dell"}]; JsonSerializer.Serialize(x, jsonSerializerOptions); 

you'd get an exception :

The type 'Submission#5+Manager' contains property 'type' that conflicts with an │ │ existing metadata property name. Consider either renaming it or ignoring it with JsonIgnoreAttribute. 

If you didn't use camel case, you'd get :

[ {"type":"Manager","Phone":"9876543210","Type":null,"Name":"Bob"}, {"type":"Developer","Laptop":"Dell","Type":null,"Name":"Charlie"} ] 

That can be deserialized if you don't use camel case.

The best choice it to not rename the discriminator, or ensure it doesn't start with $ so it can't be confused with actual types.

If you insist on using type with camel case, don't use it as a property in any entity. :

[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] [JsonDerivedType(typeof(Manager), "Manager")] [JsonDerivedType(typeof(Developer), "Developer")] public class Employee { public string Name { get; set; } } public class Manager : Employee { public string Phone { get; set; } } public class Developer : Employee { public string Laptop { get; set; } } 

In that case this :

var xx=JsonSerializer.Deserialize<Employee[]>(json,jsonSerializerOptions); 

Produces

│ Employee[] │ │ - Phone: 9876543210 │ │ Name: Bob │ │ - Laptop: MacBook Pro │ │ Name: Charlie 

If you want (or need to) keep Type as a property and write it to JSON as well as read it from JSON and have it be your discriminator, then you'll need to implement a custom JsonConverter for that, something like this

public class EmployeeConverter : JsonConverter<Employee> { public override Employee Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var doc = JsonDocument.ParseValue(ref reader); var root = doc.RootElement; // Note the lower case 't', because your JSON contains 'type' and not 'Type' var type = root.GetProperty("type").GetString(); Employee employee = type switch { "Manager" => JsonSerializer.Deserialize<Manager>(root.GetRawText(), options), "Developer" => JsonSerializer.Deserialize<Developer>(root.GetRawText(), options), // Alternatively throw an Exception _ => JsonSerializer.Deserialize<Employee>(root.GetRawText(), options) }; return employee!; } public override void Write(Utf8JsonWriter writer, Employee value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, value, value.GetType(), options); } } 

You can check out a sample on dotnetfiddle here

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.