I am using Json.NET 7.0.1.
The documentation says that
Enum
[is serialized as] Integer (can be the enum value name with StringEnumConverter)
In my Global.asax.cs, I specify the default settings as follows:
JsonConvert.DefaultSettings = (() =>
{
var settings = new JsonSerializerSettings();
settings.Converters.Add(new StringEnumConverter());
return settings;
});
However, in certain situations, I want Enums
to be serialized as integers, for instance when I build a JSON which is to be stored in the database.
Here is how I went about it:
public class JsonSerializedType<T> : IUserType where T : class
{
private static readonly JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
cmd.Parameters[index].Value = JsonConvert.SerializeObject(value as T, serializerSettings);
}
}
However, even in this case Enums
are serialized as strings. I checked that serializerSettings
has no Converters
and its ContractResolver
is null
.
Why is that so?
This is happening because JsonConvert.SerializeObject
applies the incoming settings on top of the default settings, by internally calling JsonSerializer.CreateDefault(JsonSerializerSettings settings)
. I don't know if/where this behavior is documented, but it's visible in the source code. Thus the default list of converters will be used in addition to the empty list of locally specified converters, meaning the default StringEnumConverter
will get used.
You have a couple options to work around this:
Construct the JsonSerializer
yourself without using the default settings:
public static class JsonExtensions
{
public static string SerializeObjectNoDefaultSettings(object value, Formatting formatting, JsonSerializerSettings settings)
{
var jsonSerializer = JsonSerializer.Create(settings);
jsonSerializer.Formatting = formatting;
StringBuilder sb = new StringBuilder(256);
StringWriter sw = new StringWriter(sb, CultureInfo.InvariantCulture);
using (JsonTextWriter jsonWriter = new JsonTextWriter(sw))
{
jsonWriter.Formatting = jsonSerializer.Formatting;
jsonSerializer.Serialize(jsonWriter, value);
}
return sw.ToString();
}
}
And then use it like:
var json = JsonExtensions.SerializeObjectNoDefaultSettings(value, Formatting.None, new JsonSerializerSettings());
Supersede the default StringEnumConverter
with one that does not serialize enums as strings, for instance:
public class IntegerEnumConverter : StringEnumConverter
{
public override bool CanRead { get { return false; } }
public override bool CanWrite { get { return false; } }
}
And then use it like:
var json = JsonConvert.SerializeObject(value, Formatting.None, new JsonSerializerSettings { Converters = new JsonConverter[] { new IntegerEnumConverter() } });
The locally specified converter will be picked up in preference to the default converter.
Temporarily nulling out the JsonConvert.DefaultSettings
would be a bad idea since it would not be thread-safe.
The behavior we see here is by design, passed settings in JsonConvert
methods are getting merged with provided DefaultSettings
, Here is a small part of Json.Net source code from JsonSerializer class to demystify the situation.
private static void ApplySerializerSettings(JsonSerializer serializer, JsonSerializerSettings settings)
{
if (!CollectionUtils.IsNullOrEmpty(settings.Converters))
{
// insert settings converters at the beginning so they take precedence
// if user wants to remove one of the default converters they will have to do it manually
for (int i = 0; i < settings.Converters.Count; i++)
{
serializer.Converters.Insert(i, settings.Converters[i]);
}
}
As we can see Converters are merged with provided Default ones albeit with higher precedence.
We can take advantage of higher precedence of recently merged converters and prevent StringEnumConverter
conversion.
class PreventStringEnumConverter : StringEnumConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var type = value.GetType();
var undertype = Enum.GetUnderlyingType(type);
var converted=Convert.ChangeType(value, undertype);
writer.WriteValue(converted);
}
}
and the usage would be like:
var json = JsonConvert.SerializeObject(obj,
new JsonSerializerSettings
{
Converters = new List<JsonConverter> {new PreventStringEnumConverter()}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With