gpt4 book ai didi

c# - 通过字符串转换反序列化枚举时,如何获得空值而不是序列化错误?

转载 作者:太空狗 更新时间:2023-10-29 21:37:23 27 4
gpt4 key购买 nike

我的一些 API 端点具有包含枚举的模型。 FluentValidation 用于验证发送的值是否满足各自的要求。

为了提高可用性和文档生成,允许将枚举作为字符串而不是整数发送。如果发送无效整数,则验证发送的值是否在正确范围内工作正常,但如果发送无效字符串,序列化将失败。

public enum Foo 
{
A = 1,
B = 2
}

public class Bar
{
public Foo? Foo {get;set;}
}

void Main()
{
var options = new JsonSerializerOptions();
options.Converters.Add(new JsonStringEnumConverter());
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;

var jsonString = "{\"foo\": \"C\"}";
var jsonSpan = (ReadOnlySpan<byte>)Encoding.UTF8.GetBytes(jsonString);

try
{
var result = JsonSerializer.Deserialize<Bar>(jsonSpan, options);
Console.WriteLine(result.Foo == null);
}
catch(Exception ex)
{
Console.WriteLine("Serialization Failed");
}
}

我想要的结果是,当字符串与枚举的任何字段都不匹配时,将枚举属性简单地反序列化为 null,以便可以将模型传递给验证器以创建友好消息。

我怎样才能做到这一点?这是将 net-core 3 preview 8 与 System.Text.Json API 结合使用。

最佳答案

据我所知,我有 2 种解决方案,一种使用 System.Text.Json,另一种是 Newtonsoft

System.Text.Json

您使用 JsonConverter 创建自定义类

您在 Foo 中引入未知枚举。

而不是使用 JsonStringEnumConverter

options.Converters.Add(new JsonStringEnumConverter());

使用自定义类CustomEnumConverter

options.Converters.Add(new CustomEnumConverter());

所以让我们把事情放在一起:

public enum Foo
{
A = 1,
B = 2,
// what ever name and enum number that fits your logic
Unknown = 99
}

public class Bar
{
public Foo? Foo { get; set; }
}

public static void Main()
{
var options = new JsonSerializerOptions();
options.Converters.Add(new CustomEnumConverter());
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;

var jsonString = "{\"foo\": \"C\"}";
var jsonSpan = (ReadOnlySpan<byte>)Encoding.UTF8.GetBytes(jsonString);

try
{
var result = JsonSerializer.Deserialize<Bar>(jsonSpan, options);

if (result.Foo == Foo.Unknown)
result.Foo = null;

Console.WriteLine(result.Foo == null);
}
catch (Exception ex)
{
Console.WriteLine("Serialization Failed" + ex.Message);
}
}

这里是代码 CustomEnumConverter

internal sealed class CustomEnumConverter : JsonConverter<Foo>
{
public override Foo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
switch (reader.TokenType)
{
case JsonTokenType.String:
var isNullable = IsNullableType(typeToConvert);
var enumType = isNullable ? Nullable.GetUnderlyingType(typeToConvert) : typeToConvert;
var names = Enum.GetNames(enumType ?? throw new InvalidOperationException());
if (reader.TokenType != JsonTokenType.String) return Foo.Unknown;
var enumText = System.Text.Encoding.UTF8.GetString(reader.ValueSpan);
if (string.IsNullOrEmpty(enumText)) return Foo.Unknown;
var match = names.FirstOrDefault(e => string.Equals(e, enumText, StringComparison.OrdinalIgnoreCase));
return (Foo) (match != null ? Enum.Parse(enumType, match) : Foo.Unknown);
default:
throw new ArgumentOutOfRangeException();
}
}

public override void Write(Utf8JsonWriter writer, Foo value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}

private static bool IsNullableType(Type t)
{
return (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
}
}

运行此代码应无异常返回 True。

对于此解决方案,我从 here 中获得了一些灵感。 .

另一种方法有点类似,但使用的是 Newtonsoft。

Note: Remember what I did here is just example to demonstrate stuff, please validate every thing, test it before going production.

Newtonsoft(原始答案)

使用带有自定义 JsonConverterNewtonsoft 解决此问题的另一种方法。

您所做的是将自定义 JsonConverter 的属性添加到您的 Foo 类 [JsonConverter(typeof(CustomEnumConverter))]

如果 enum 无法识别,则让您的类方法返回 null

您当然可以自定义几乎任何类型并具有不同的自定义类。

确定通过 Nuget 管理器安装 Newtonsoft.Json nuget 包。

我们从您的代码修改开始:

//add the attribute here
[JsonConverter(typeof(CustomEnumConverter))]
public enum Foo
{
A = 1,
B = 2
}

public class Bar
{
public Foo? Foo { get; set; }
}

public static void Main()
{
var jsonString = "{\"foo\": \"C\"}";

try
{
// use newtonsoft json converter
var result = JsonConvert.DeserializeObject<Bar>(jsonString);
Console.WriteLine(result.Foo == null);
}
catch (Exception ex)
{
Console.WriteLine("Serialization Failed" + ex.Message);
}
}

现在为您的自定义类:

public class CustomEnumConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
var type = IsNullableType(objectType) ? Nullable.GetUnderlyingType(objectType) : objectType;
return type != null && type.IsEnum;
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var isNullable = IsNullableType(objectType);
var enumType = isNullable ? Nullable.GetUnderlyingType(objectType) : objectType;
var names = Enum.GetNames(enumType ?? throw new InvalidOperationException());

if (reader.TokenType != JsonToken.String) return null;
var enumText = reader.Value.ToString();

if (string.IsNullOrEmpty(enumText)) return null;
var match = names.FirstOrDefault(e => string.Equals(e, enumText, StringComparison.OrdinalIgnoreCase));

return match != null ? Enum.Parse(enumType, match) : null;
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(value.ToString());
}

public override bool CanWrite => true;

private static bool IsNullableType(Type t)
{
return (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
}
}

现在是测试时间。

当我们在没有 [JsonConverter(typeof(CustomEnumConverter))] 的情况下启动程序时,我们会收到如下所示的错误: enter image description here

但是当我们添加 [JsonConverter(typeof(CustomEnumConverter))] 并再次运行该程序时,它起作用了: enter image description here

链接:

关于c# - 通过字符串转换反序列化枚举时,如何获得空值而不是序列化错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57893720/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com