1 year ago
#76055

Vic F
JSON Converter changing case of values in netcoreapp3.1 web api
I have an enum extension that allows for enums to be transformed into their [Description]
value, as in:
private enum WithDescription
{
[Description("Nothing")] None = 0,
[Description("Some of it")] Some,
[Description("All of it")] All
}
public static class EnumExtensions
{
public static string GetDescription<T>(this T enumerationValue) where T : struct, Enum
{
var type = enumerationValue.GetType();
if (!type.IsEnum)
{
throw new ArgumentException($"{nameof(T)} must be of type Enum.");
}
var memberInfo = type.GetMember(enumerationValue.ToString());
if (memberInfo.Length > 0)
{
var attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs.Length > 0)
{
return ((DescriptionAttribute) attrs[0]).Description;
}
}
return enumerationValue.ToString();
}
public static T GetEnumByDescription<T>(this string text) where T : struct, Enum
{
var type = typeof(T);
if (!type.IsEnum)
{
throw new ArgumentException($"{nameof(T)} must be of type Enum.");
}
MemberInfo[] members = type.GetMembers(BindingFlags.Public | BindingFlags.Static);
foreach (MemberInfo member in members)
{
var attrs = member.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs.Length > 0)
{
for (int i = 0; i < attrs.Length; i++)
{
string description = ((DescriptionAttribute) attrs[i]).Description;
if (text.Equals(description, StringComparison.OrdinalIgnoreCase))
{
return (T) Enum.Parse(type, member.Name, true);
}
}
}
if (member.Name.Equals(text, StringComparison.OrdinalIgnoreCase))
{
return (T) Enum.Parse(type, member.Name, true);
}
}
return default;
}
public static IEnumerable<string> GetDescriptions<T>() where T : struct, Enum
{
MemberInfo[] members = typeof(T).GetMembers(BindingFlags.Public | BindingFlags.Static);
foreach (MemberInfo member in members)
{
var attrs = member.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs.Length > 0)
{
for (int i = 0; i < attrs.Length; i++)
{
string description = ((DescriptionAttribute) attrs[i]).Description;
yield return description;
}
}
else
{
yield return member.Name;
}
}
}
}
And, I have a custom System.Text.Json
converter:
public class EnumDescriptionConverterFactory : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert) => typeToConvert.IsEnum;
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) =>
(JsonConverter?) Activator.CreateInstance(
typeof(EnumConverterInner<>).MakeGenericType(new Type[] {typeToConvert}),
BindingFlags.Instance | BindingFlags.Public,
binder: null,
args: null,
culture: null);
private class EnumConverterInner<T> : JsonConverter<T> where T : struct, Enum
{
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string? propertyName = reader.GetString();
MemberInfo[] members = typeToConvert.GetMembers(BindingFlags.Public | BindingFlags.Static);
foreach (MemberInfo member in members)
{
var attrs = member.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs.Length > 0)
{
foreach (var t in attrs)
{
string description = ((DescriptionAttribute) t).Description;
if (propertyName?.Equals(description, StringComparison.OrdinalIgnoreCase) ?? false)
{
return (T) Enum.Parse(typeToConvert, member.Name, true);
}
}
}
if (member.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase))
{
return (T) Enum.Parse(typeToConvert, member.Name, true);
}
}
if (!Enum.TryParse(propertyName, false, out T result) &&
!Enum.TryParse(propertyName, true, out result))
{
throw new JsonException(
$"Unable to convert \"{propertyName}\" to Enum \"{typeToConvert}\".");
}
return result;
}
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
Type type = value.GetType();
var memberInfo = type.GetMember(value.ToString());
if (memberInfo.Length > 0)
{
var attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs.Length > 0)
{
var description = ((DescriptionAttribute) attrs[0]).Description;
writer.WriteStringValue(options.PropertyNamingPolicy?.ConvertName(description) ?? description);
}
else
{
writer.WriteStringValue(options.PropertyNamingPolicy?.ConvertName(value.ToString()) ??
value.ToString());
}
}
}
}
This code all works perfectly in every way I could test it, but when I plug it into a netcoreapp3.1
web api application, it converts the description to all lowercase in the output. In my tests, I get "Some of it" and in actual output from an API endpoint, I get "some of it"
In my ConfigureServices
I have:
services.AddControllers(options =>
options.Filters.Add(new HttpResponseExceptionFilter())).AddJsonOptions(GetJsonOptions());
and the function being called is:
private static Action<JsonOptions> GetJsonOptions()
{
return options =>
{
options.JsonSerializerOptions.IgnoreNullValues = true;
options.JsonSerializerOptions.MaxDepth = 64;
options.JsonSerializerOptions.Converters.Add(new EnumDescriptionConverterFactory());
};
}
As I wrote, I'm sure it's "working" because the transformation takes place, but the output is always lower case.
Anyone know why this might be happening or what I could do about it?
c#
asp.net-core-webapi
asp.net-core-3.1
system.text.json
json-serialization
0 Answers
Your Answer