gpt4 book ai didi

c# - Web Api 错误地反序列化枚举列表

转载 作者:太空狗 更新时间:2023-10-29 22:59:26 26 4
gpt4 key购买 nike

因此,我正在使用 Web API Controller 来接受 JSON 请求。它映射到包含枚举列表的模型对象。我遇到的问题是,如果 JSON 包含无效值,它似乎没有正确反序列化。我希望将无效值映射到我的枚举列表中的 0 值类型,但是这并没有发生。

我隔离了 3 种主要情况:如果 JSON 的形式为

    ...
"MyEnumList":["IncorrectEnum", "One", "Two"]
...

该值根本没有映射,我只是得到一个包含两个有效值的列表。但是,如果我提供此 JSON:

   ...
"MyEnumList":["123", "One", "Two"]
...

我得到一个包含 3 个对象的列表,其中第一个对象的类型为“MyEnum”并且值为 123,即使我的枚举中没有定义它。如果我提供此 JSON 语法,也会发生同样的情况:

   ...
"MyEnumList":[123, "One", "Two"]
...

谁能解释这里发生了什么,以及我如何确保值始终映射到有效类型?

供引用,模型对象,其中包含我的枚举列表:

    public class MyClass
{
public List<myEnum> MyEnumList { get; set; }
}

和简单的枚举:

    public enum myEnum 
{
Zero = 0,
One = 1,
Two = 2
}

最佳答案

123 可以分配给不包含 123 值的枚举这一事实并不完全是 Json.Net 的错。事实证明,C# 运行时本身允许这种赋值。如果您运行这个小型演示程序,您可以亲眼看到:

class Program
{
static void Main(string[] args)
{
// Direct cast from integer -- no error here
MyEnum x = (MyEnum)123;
Console.WriteLine(x);

// Parsing a numeric string -- no error here either
MyEnum y = (MyEnum)Enum.Parse(typeof(MyEnum), "456");
Console.WriteLine(y);
}

public enum MyEnum
{
Zero = 0,
One = 1,
Two = 2
}
}

所以可能发生的情况是 Json.Net 只是在幕后使用 Enum.Parse。但是,我不知道为什么您在第一个案例中没有得到异常(exception)。当我尝试这样做时,它失败了(如我所料)。

在任何情况下,如果您需要对可能错误的枚举值进行严格验证,您可以创建一个自定义 JsonConverter 来强制该值有效(或选择性地抛出异常)。这是一个适用于任何类型枚举的转换器。 (代码可能需要改进,但它确实有效。)

class StrictEnumConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType.BaseType == typeof(Enum));
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);

try
{
// We're only interested in integers or strings;
// all other token types should fall through
if (token.Type == JTokenType.Integer ||
token.Type == JTokenType.String)
{
// Get the string representation of the token
// and check if it is numeric
string s = token.ToString();
int i;
if (int.TryParse(s, out i))
{
// If the token is numeric, try to find a matching
// name from the enum. If it works, convert it into
// the actual enum value; otherwise punt.
string name = Enum.GetName(objectType, i);
if (name != null)
return Enum.Parse(objectType, name);
}
else
{
// We've got a non-numeric value, so try to parse it
// as is (case insensitive). If this doesn't work,
// it will throw an ArgumentException.
return Enum.Parse(objectType, s, true);
}
}
}
catch (ArgumentException)
{
// Eat the exception and fall through
}

// We got a bad value, so return the first value from the enum as
// a default. Alternatively, you could throw an exception here to
// halt the deserialization.
IEnumerator en = Enum.GetValues(objectType).GetEnumerator();
en.MoveNext();
return en.Current;
}

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

这是一个在值的大杂烩上使用转换器的演示:

class Program
{
static void Main(string[] args)
{
// The first 12 values should deserialize to correct values;
// the last 7 should all be forced to MyEnum.Zero.
string json = @"
{
""MyEnumList"":
[
""Zero"",
""One"",
""Two"",
0,
1,
2,
""zero"",
""one"",
""two"",
""0"",
""1"",
""2"",
""BAD"",
""123"",
123,
1.0,
null,
false,
true
]
}";

MyClass obj = JsonConvert.DeserializeObject<MyClass>(json,
new StrictEnumConverter());
foreach (MyEnum e in obj.MyEnumList)
{
Console.WriteLine(e.ToString());
}
}

public enum MyEnum
{
Zero = 0,
One = 1,
Two = 2
}

public class MyClass
{
public List<MyEnum> MyEnumList { get; set; }
}
}

这是输出:

Zero
One
Two
Zero
One
Two
Zero
One
Two
Zero
One
Two
Zero
Zero
Zero
Zero
Zero
Zero
Zero

顺便说一句,要将此转换器与 Web API 一起使用,您需要将此代码添加到 Global.asax.cs 中的 Application_Start() 方法中:

JsonSerializerSettings settings = GlobalConfiguration.Configuration.Formatters 
.JsonFormatter.SerializerSettings;
settings.Converters.Add(new StrictEnumConverter());

关于c# - Web Api 错误地反序列化枚举列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21296149/

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