用枚举数组反序列化json

时间:2020-01-31 06:11:43

标签: c# asp.net json.net asp.net-core-webapi asp.net-core-3.1

使用枚举:

namespace AppGlobals
{
    [JsonConverter(typeof(JsonStringEnumConverter))]
    public enum BoardSymbols
    {
        [EnumMember(Value = "X")]
        First = 'X',
        [EnumMember(Value = "O")]
        Second = 'O',
        [EnumMember(Value = "?")]
        EMPTY = '?'
    }
}

我想为我的api定义一个模型:

using System;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using Newtonsoft.Json;

namespace Assignment_1
{
    public class MyRequest
    {
//...
        [Required]
        [MinLength(9)]
        [MaxLength(9)]
        [JsonProperty("changeTypes", ItemConverterType = typeof(JsonStringEnumConverter))]
        public AppGlobals.BoardSymbols[] GameBoard { get; set; }
    }
}

GameBoard应该在其中以EnumMember属性指定的名称的字符串数组形式序列化为JSON。此方法改编自Deserialize json character as enumeration。但是,它不起作用。如果我将枚举更改为:

    [JsonConverter(typeof(JsonStringEnumConverter))]
    public enum BoardSymbols
    {
      X='X',
      Y='Y'
    }

但是我显然对“空”枚举达到了极限。我该怎么办?

更新2:

我在启动时没有AddNewtonsoftJson(),而是完全转换为Newtonsoft。现在我的错误也许更具可执行性:

System.InvalidCastException: Unable to cast object of type 'CustomJsonStringEnumConverter' to type 'Newtonsoft.Json.JsonConverter'.
   at Newtonsoft.Json.Serialization.JsonTypeReflector.CreateJsonConverterInstance(Type converterType, Object[] args)

这是有道理的,here所指定的解决方案指定了一个JsonConverterFactory。我只需要原始的JsonConverter作为我的用例即可。

1 个答案:

答案 0 :(得分:1)

TL / DR:您在这里有两个基本问题:

  1. .NET Core 3.0+具有new built-in JSON serializer System.Text.Json,并且您正在此新的序列化程序和Json.NET之间混合属性和类。两者都安装时,这很容易做到,因为它们共享一些类名,例如JsonSerializerJsonConverter

  2. 默认情况下使用新的序列化器,但尚不支持将枚举序列化为具有自定义值名称的字符串;有关详情,请参见 System.Text.Json: How do I specify a custom name for an enum value?

解决问题的最简单方法是如图here所示切换回Json.NET,并仅使用此序列化程序中的属性,转换器和名称空间。

首先让我们分解两个序列化器之间的差异和相似之处:

  1. System.Text.Json

  2. Json.NET:

牢记这一点,您在代码中使用哪个序列化程序?由于您在问题中有用地包含了名称空间,因此我们可以检查:

using System.Text.Json.Serialization; // System.Text.Json
using Newtonsoft.Json;                // Json.NET

namespace Assignment_1
{
    public class MyRequest
    {
//...
        [JsonProperty(                                         // JsonProperty from Newtonsoft
            "changeTypes", 
            ItemConverterType = typeof(JsonStringEnumConverter)// JsonStringEnumConverter from System.Text.Json
        )]
        public AppGlobals.BoardSymbols[] GameBoard { get; set; }
    }
}

如您所见,您正在将来自Newtonsoft的属性与来自System.Text.Json的转换器进行混合,这是行不通的。 (也许您在Visual Studio中右键单击“解析->使用...”选择了名称空间?)

那么,如何解决问题?由于Json.NET支持开箱即用地重命名枚举值,因此解决此问题的最简单方法是使用此序列化器。尽管性能可能不如System.Text.Json,但它更加完整和功能齐全。

为此,请在您的代码中删除命名空间System.Text.Json.SerializationSystem.Text.Json以及对类型JsonStringEnumConverter的引用,并修改MyRequestBoardSymbols如下:

using System.Runtime.Serialization;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json;

namespace Assignment_1
{
    public class MyRequest
    {
//...
        [Required]
        [MinLength(9)]
        [MaxLength(9)]
        [JsonProperty("changeTypes")] // No need to add StringEnumConverter here since it's already applied to the enum itself
        public AppGlobals.BoardSymbols[] GameBoard { get; set; }
    }
}

namespace AppGlobals
{
    [JsonConverter(typeof(StringEnumConverter))]
    public enum BoardSymbols
    {
        [EnumMember(Value = "X")]
        First = 'X',
        [EnumMember(Value = "O")]
        Second = 'O',
        [EnumMember(Value = "?")]
        EMPTY = '?'
    }
}

然后NuGet Microsoft.AspNetCore.Mvc.NewtonsoftJson并在Startup.ConfigureServices中调用AddNewtonsoftJson()

services.AddMvc()
    .AddNewtonsoftJson();

或者,如果您希望全局使用StringEnumConverter

services.AddMvc()
    .AddNewtonsoftJson(o => o.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()));

请注意docs

中的以下评论

注意:如果无法使用AddNewtonsoftJson方法,请确保已安装Microsoft.AspNetCore.Mvc.NewtonsoftJson软件包。常见错误是安装Newtonsoft.Json软件包而不是Microsoft.AspNetCore.Mvc.NewtonsoftJson软件包。

样机小提琴here