I have a production api returning the below json:
[
{
"StartUtc": "2023-09-02T13:52:00Z",
"EndUtc": "2023-09-02T15:19:00Z",
"isCustomerInStore": false,
"productLead": {
"id": 1,
"leadType": "PREVIOUS_CUSTOMER",
"leadStatus": "SOLD_DELIVERED",
"leadStatusType": "SOLD",
"leadSourceId": 11,
"leadSourceName": "Previous Customer"
},
"customer": {
"id": 1,
"firstName": "Jane",
"lastName": "Doe",
"salesRepresentative": {
"id": 1,
"firstName": "Sales",
"lastName": "Guy1",
"assignedUserType": "SALES_REPRESENTATIVE"
}
},
"product": {
"year": 2023,
"make": "Google",
"model": "Pixel",
"stockNumber": "ABCD1234"
}
}
]
After the serialization of the above json, my api returns the below.
[
{
"StartUtc": "2023-09-02T13:52:00Z",
"EndUtc": "2023-09-02T15:19:00Z",
"isCustomerInStore": false,
"productLead": {
"id": 1,
"leadType": "previouS_CUSTOMER",
"leadStatus": "solD_DELIVERED",
"leadStatusType": "sold",
"leadSourceId": 11,
"leadSourceName": "Previous Customer"
},
"customer": {
"id": 1,
"firstName": "Jane",
"lastName": "Doe",
"salesRepresentative": {
"id": 1,
"firstName": "Sales",
"lastName": "Guy1",
"assignedUserType": "saleS_REPRESENTATIVE"
}
},
"product": {
"year": 2023,
"make": "Google",
"model": "Pixel",
"stockNumber": "ABCD1234"
}
}
]
The leadType
, leadStatus
, leadStatusType
& assignedUserType
are enum fields having attributes [JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
. Also, all the enums have the attribute [JsonConverter(typeof(JsonStringEnumConverter))]
. But they are returning with first few characters serialized to lower characters? Any ideas why?
"previouS_CUSTOMER"
is the camel case serialization of PREVIOUS_CUSTOMER
generated by System.Text.Json. Somewhere in your startup method you must be constructing a JsonStringEnumConverter
using JsonNamingPolicy.CamelCase
, e.g. in Program.cs
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.Converters.Add(
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)); // HERE
});
To prevent this, you have a few options:
Firstly, if you never want camel case serialization of enums, just don't use JsonNamingPolicy.CamelCase
with JsonStringEnumConverter
:
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.Converters.Add(
new JsonStringEnumConverter());
});
You can still use camel case for your property names.
Secondly, if you want camel case serialization of enums for most enums but not your LeadType
enum, use OptOutJsonConverterFactory
from this answer to Exclude an enum property of a Model from using the JsonStringEnumConverter which is globally set at the Startup? to disable its use for LeadType
:
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.Converters.Add(
new OptOutJsonConverterFactory(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase),
typeof(LeadType)));
// Add a non-camel-case fallback converter for the opted out enum types:
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
Demo fiddle #1 here.
Finally, if you don't want camel case enum serialization for the LeadType
property, apply [System.Text.Json.Serialization.JsonConverter(typeof(JsonStringEnumConverter))]
to the property like so:
public class ProductLead
{
[System.Text.Json.Serialization.JsonConverter(
typeof(System.Text.Json.Serialization.JsonStringEnumConverter))]
public LeadType LeadType { get; set; }
// Other properties omitted
}
Demo fiddle #2 here.
Notes:
As explained in the docs, converters are chosen with the following precedence:
[JsonConverter]
applied to a property.- A converter added to the
Converters
collection.[JsonConverter]
applied to a custom value type or POCO.
As you can see, converters added to options supersede converters applied to types (but not properties). This is why applying [JsonConverter(typeof(JsonStringEnumConverter))]
to your enum types did not solve the problem.
You wrote that you applied
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
To each property type, but StringEnumConverter
is from Newtonsoft.Json, a completely different serializer. System.Text.Json has an attribute JsonConverterAttribute
with the same name as Newtonsoft's JsonConverterAttribute
so it's easy to get them confused. When using both serializers, I recommend using the fully qualified name for metadata attributes.