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

2023-11-24

因此,我使用 Web API 控制器来接受 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在幕后。然而,我不知道为什么你的第一个案例没有得到例外。当我尝试这样做时,它失败了(正如我所期望的)。

无论如何,如果您需要严格验证可能错误的枚举值,您可以创建一个自定义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 一起使用,您需要将此代码添加到您的Application_Start()中的方法Global.asax.cs:

JsonSerializerSettings settings = GlobalConfiguration.Configuration.Formatters 
                                  .JsonFormatter.SerializerSettings;
settings.Converters.Add(new StrictEnumConverter());
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Web Api 错误地反序列化枚举列表 的相关文章

  • “字符串”是什么意思?信息'

    我刚刚在查看定义时发现了这个PlatformNotSupportedException class 什么是string message意思是 据我所知是 是缩写Nullable lt gt but Nullable lt gt 只能应用于结
  • 如何重命名序列化对象列表后生成的 XML 属性

    我正在序列化对象列表List
  • 如何将不记名令牌发送到 ASP NET MVC 5 中的视图?

    我有一个 NET MVC and WEB API项目 我想打电话给WEB API controllers来自 javascript 但我没有找到将令牌发送到我的视图的方法 我想添加bearer token in Viewbag变量 使用以下
  • 在 C# 中轻松创建支持索引的属性

    在 C 中我发现索引属性 http msdn microsoft com en us library aa288464 VS 71 aspx非常有用 例如 var myObj new MyClass myObj 42 hello Conso
  • 在目标 VS 安装时,VSIX 扩展内部使用的 WPF-Log4Net 未输出日志

    当 Log4net 在 VSIX 扩展中使用并安装在另一个目标 VS 上时 它不会记录日志 我有一个 WPF 解决方案 我下载了 log4net dll 添加了 log4net config 并将 复制到输出目录 值设置为 始终复制 log
  • 我的 WPF 应用程序未触发 MainWindow_Loaded

    我目前正在关注Pluralsight C Fundamentals Part 1并在Classes and Objects视频部分指导我在 Visual Studio 中创建一个新的 WPF 应用程序并填写代码 这导致以下结果 namesp
  • 为什么我不能从对中返回 unique_ptr?

    为什么我不能从对中返回 unique ptr include
  • 以编程方式运行 T4 文本模板

    有没有一种方法可以通过代码以编程方式运行 T4 文本模板 我正在制作一种自定义域特定语言 我希望相关的文本模板在用户每次保存时运行 目前 这就是我在 DSL 模型中所做的事情 protected override void OnDocume
  • 从套接字读取 C HTTP

    我想知道如何判断是否已从套接字接收到所有数据 这是一个简单的网络代理 现在我正在处理请求部分 所以发送的内容应该以 r n r n 结尾 我不知道请求会持续多久 我在这里读过一些帖子 说我应该检查读取函数是否返回 0 但其他人说0只在客户端
  • 修改正在运行的可执行文件的资源内容

    All 我将应用程序设置存储在资源中 当我的程序首次加载时 我使用 WinAPI 读取指定的资源 然后我解析检索到的字节数据 这对我来说完美无缺 现在假设用户更改了我的应用程序中的设置 他 她检查复选框控件 我想将更新的设置保存到我的资源中
  • 为什么 httpRuntime targetFramework="4.5" 禁止抓取 .ASPXAUTH cookie?

    当我的 web config 具有以下 httpRuntime 时 我的控制器无法获取 cookie ASPXAUTH 它似乎能够获取任何其他 cookie 无论带或不带句点前缀 如果我删除下面的行 它就可以正常工作
  • 为什么我无法调试动态加载的程序集?

    我正在开发一个 Web API 项目 该项目使用内部模拟框架 允许拦截和修改来自控制器的响应 它使用 MEF 加载包含某些先决条件匹配时执行的代码的程序集 我知道这是正常工作的 因为我可以在响应中看到模拟已被执行 但由于某种原因我无法调试动
  • 类型别名和不完整类型

    我可能已经超出了解决这个本应简单的问题的范围 我在这里开始这个问题 在编译时获取基类的类型 https stackoverflow com questions 17735852 getting type of a base class at
  • 为什么必须通过 this 指针访问模板基类成员?

    如果下面的类不是模板 我可以简单地拥有x in the derived班级 但是 通过下面的代码 我have to use this gt x Why template
  • 使用 _Alignas 进行结构成员对齐

    我想知道以下问题 是新的吗 Alignas结盟 C11 中的说明符适用于结构成员吗 我一直假设这么多 但彻底阅读了 N1570 公开草案似乎表明对齐说明符不能 出现在一个说明符限定符列表 这就是我所期望的 如果得到支持的话 我已经读过几遍语
  • 如何创建和使用类箭头运算符? [复制]

    这个问题在这里已经有答案了 因此 在到处研究之后 我似乎找不到如何创建类箭头运算符 即 class Someclass operator gt 我只需要知道如何使用它并正确使用它 它的输入是什么 它返回什么 我如何正确地声明 原型化它 运算
  • Gridview 错误:对 Bind 的调用格式不正确

    我有以下 gridview 代码
  • 将多个 Blob 输入传递到 QueueTrigger Azure 函数的最佳方法

    问题 触发后 生成 3 个 XML 文件 完成后将它们通过 ftp 传输到站点 目前的方法 我有一个 HTTP 触发器 Azure 函数 运行时将构造 3 个 XML 文件并将它们保存到 Azure 存储 Blob 容器中 由于有多个输出
  • char[length]初始化并处理

    我定义了一个字符数组 char d 6 如果我在以下方面有误 请纠正我 此时没有为变量分配内存d 现在我要初始化它 d aaaaa 这种初始化之后 就不需要释放内存了 它将自动完成 我怎么知道是否char 被初始化了吗 我正在寻找类似的模式
  • 替换全局热键

    我有一个位于托盘中的应用程序 我想定义多个热键来触发我的程序中的事件 我从 AaronLS 在这个问题中的出色回答中找到了灵感 使用C 设置全局热键 https stackoverflow com a 27309185 3064934 如果

随机推荐

  • android studio设置java版本1.7

    我正在尝试将 java 版本 1 7 与 android studio 一起使用 但不幸的是它无法正常工作 如果将版本设置为File gt Other settings gt Default project structure to Pro
  • 如何在 Cucumber Java 的步骤之间传递变量值?

    我有一个变量 我想在所有步骤中传递该变量 任何人都可以使用代码片段示例来建议如何在步骤之间传递变量值 任何帮助将不胜感激 在 Cucumber for Java cucumber jvm 中 在步骤之间共享数据的预期方式是使用依赖项集成 D
  • 在其自己的成员函数中构造类时,如何强制类模板参数推导?

    考虑以下代码 struct A template
  • Servlet 容器和类路径

    Servlet 容器的类路径集是什么 根据我的理解 涉及三个组成部分 JAR 文件位于libServlet 容器的目录 然后是 Servlet 中的类WEB INF classes和 JAR 文件在WEB INF lib目录 班级在libS
  • 非空字段的流畅 Nhibernate Automap 约定

    有人可以帮忙吗 我如何指示 automap 不为空 一个专栏 public class Paper Entity public Paper DomainSignature NotNull NotEmpty public virtual st
  • 使用 jQuery 获取最后一个可见元素

    table tr class here td 1 td tr tr class here td 2 td tr tr class here style display none td 3 td tr tr class here style
  • PDO 错误消息? [复制]

    这个问题在这里已经有答案了 这是我的代码片段 qry INSERT INTO non existant table id score SELECT id 40 FROM another non existant table WHERE de
  • 在 Swift 中,Array [String] 切片返回类型似乎不是 [String]

    我正在切片一个字符串数组并将其设置为 String 变量 但类型检查器抱怨 这可能是编译器错误吗 var tags this is cool tags 1 lt 3 var someTags String tags 1 lt 3 用范围作为
  • Symfony2 - 动态表单选择 - 验证删除

    我有一个下拉表单元素 最初它是空的 但在用户进行一些交互后 它会通过 javascript 填充值 这一切都工作正常 但是 当我提交时 它总是返回验证错误This value is not valid 如果我将项目添加到表单代码中的选择列表
  • 如何将索引器与具有参数和函数调用的扩展方法一起使用

    是否可以使用indexers with extension方法 例如 仅将其视为示例 public static object SelectedValue this DataGridView dgv string ColumnName re
  • 如何检测 Protocol Buffer 消息何时被完全接收?

    这是我的一个分支其他问题 如果您愿意 请阅读它 但这不是必需的 基本上 我意识到 为了在大消息上有效使用 C 的 BeginReceive 我需要 a 首先读取数据包长度 然后准确读取那么多字节 或者 b 使用数据包结尾分隔符 我的问题是
  • 的替代方案

    The tag从来都不是官方标准 现在已被所有浏览器完全放弃 是否有符合标准的方法使文本闪烁 blink text animation 1s blinker linear infinite webkit animation 1s blink
  • 当 php 脚本仍在执行时回显消息

    我有一个使用 cURL 的 php 脚本 执行大约需要 10 15 分钟 它的作用是 它解析大约 1000 个页面以查找特定的匹配项 并且在整个脚本中我都会回显诊断消息 例如 转到下一页 找到匹配项 加载页面时出错 它现在的工作方式 也是正
  • 如何修复尝试通过改造抛出 OutOfMemoryError 时抛出的 OutOfMemoryError

    我正在使用 Retrofit 在我的应用程序中下载一些媒体文件 如视频 mp3 jpg pdf 当我想下载 55MB 的 mp4 格式的大文件时 这是一个问题 当我想下载这个文件时 我收到如下错误 OutOfMemoryError thre
  • 如何在 C# 中使用 REST,包括 PUT、POST 和 DELETE?

    我有一个 REST Web 服务 需要在 C 中使用 不过 我需要的支持不仅仅是 GET 请求 我需要 REST 完成的所有操作 包括 GET PUT POST 和 DELETE 与之交互的最佳方式是什么 我没有看到 HTTPRequest
  • 使用 Angular.js 和 Node.js 构建实时应用程序哪种更好?

    我是 Angular js 和 Node js 的初学者 但我意识到有两种可能的方法来制作实时应用程序 第一个是使用 Socket io 另一个是使用带有 setInterval 函数的 RESTful 作为客户端解决方案 我使用两种替代方
  • PHP 与 Apple 通知网关的套接字连接失败

    免责声明 所以我发现了很多类似的问题和一些答案 但没有解决我的问题 我有这个简单的 PHP 代码
  • 拦截来电ios sdk(非越狱)

    您好 我尝试了很多次 发现由于安全原因 iOS SDK 不允许我们访问以下数据 拦截来电 从来电中获取电话号码 读取通话记录 拦截短信 从收到的短信中获取电话号码并读取其内容 阻止来电 etc 以下是我搜索有关此问题的一些链接 如何从 iP
  • SQL ' ' 不会被转义

    我正在尝试通过执行以下操作在 SQL 2008 中运行查询 query varchar max SET query SELECT FROM Table WHERE Name Karl EXEC query 问题是由于某种原因周围的撇号 Ka
  • Web Api 错误地反序列化枚举列表

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