使用枚举:
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'
}
但是我显然对“空”枚举达到了极限。我该怎么办?
我在启动时没有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作为我的用例即可。
答案 0 :(得分:1)
TL / DR:您在这里有两个基本问题:
.NET Core 3.0+具有new built-in JSON serializer System.Text.Json
,并且您正在此新的序列化程序和Json.NET之间混合属性和类。两者都安装时,这很容易做到,因为它们共享一些类名,例如JsonSerializer
和JsonConverter
。
默认情况下使用新的序列化器,但尚不支持将枚举序列化为具有自定义值名称的字符串;有关详情,请参见 System.Text.Json: How do I specify a custom name for an enum value? 。
解决问题的最简单方法是如图here所示切换回Json.NET,并仅使用此序列化程序中的属性,转换器和名称空间。
首先让我们分解两个序列化器之间的差异和相似之处:
System.Text.Json
:
自动内置到.NET Core 3.0+中,并由ASP.NET Core 3.0+ by default用于JSON序列化。
包括System.Text.Json.Serialization.JsonConverter
,System.Text.Json.Serialization.JsonConverter<T>
和System.Text.Json.JsonSerializer
在内的类。
属性,包括System.Text.Json.Serialization.JsonPropertyNameAttribute
,System.Text.Json.Serialization.JsonConverterAttribute
和System.Text.Json.Serialization.JsonExtensionDataAttribute
。
System.Text.Json.Serialization.JsonStringEnumConverter
支持将枚举作为字符串序列化,但是未实现通过属性重命名。
有关可能的解决方法,请参见this answer至 System.Text.Json: How do I specify a custom name for an enum value? 。
Json.NET:
一个第三方库,可用于ASP.NET Core 3.0+中的序列化,方法是添加对Microsoft.AspNetCore.Mvc.NewtonsoftJson
的NuGet引用,然后在Startup.ConfigureServices
中调用AddNewtonsoftJson()
。
有关详细信息,请参见this answer的Where did IMvcBuilder AddJsonOptions go in .Net Core 3.0?至 poke 。
命名空间,包括Newtonsoft.Json
中的Newtonsoft.Json.Converters
,Newtonsoft.Json.Linq
,Newtonsoft.Json.Serialization
和others。
包括Newtonsoft.Json.JsonConverter
,Newtonsoft.Json.JsonConverter<T>
和Newtonsoft.Json.JsonSerializer
Newtonsoft.Json.JsonPropertyAttribute
中的Newtonsoft.Json.JsonConverterAttribute
,Newtonsoft.Json.JsonExtensionDataAttribute
和others等属性。
在应用Newtonsoft.Json.Converters.StringEnumConverter
属性时,EnumMemberAttribute
自动支持将枚举序列化为重命名字符串。
牢记这一点,您在代码中使用哪个序列化程序?由于您在问题中有用地包含了名称空间,因此我们可以检查:
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.Serialization
和System.Text.Json
以及对类型JsonStringEnumConverter
的引用,并修改MyRequest
和BoardSymbols
如下:
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。