rob*_*más 12 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 = '?'
}
}
Run Code Online (Sandbox Code Playgroud)
我想为我的 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; }
}
}
Run Code Online (Sandbox Code Playgroud)
哪里GameBoard应该序列化为 JSON 作为字符串数组,其名称由EnumMember属性指定。这种方法改编自Deserialize json character as enumeration。然而,它不起作用。如果我将枚举更改为:
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum BoardSymbols
{
X='X',
Y='Y'
}
Run Code Online (Sandbox Code Playgroud)
但我显然达到了“空”枚举的限制。我怎样才能做到这一点?
我在创业时并没有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)
Run Code Online (Sandbox Code Playgroud)
这是有道理的,这里给我规定的解决方案指定了一个 JsonConverterFactory ..我只需要原始的 JsonConverter 来代替我的用例。
TL/DR:这里有两个基本问题:
.NET Core 3.0+ 有一个新的内置 JSON 序列化器,并且您在这个新序列化器和System.Text.JsonJson.NET之间混合了属性和类。当两者都安装时,这很容易做到,因为它们共享一些类名,例如JsonSerializer和JsonConverter。
默认情况下使用新的序列化程序,但尚不支持将枚举序列化为具有自定义值名称的字符串;请参阅System.Text.Json:如何为枚举值指定自定义名称?了解详情。
解决问题的最简单方法是切换回 Json.NET,如此处所示,并仅使用此序列化程序中的属性、转换器和命名空间。
首先我们来分解一下两个序列化器之间的异同:
System.Text.Json:
自动内置于 .NET Core 3.0+ 中,并默认用于 ASP.NET Core 3.0+ 的 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,但未实现通过属性重命名。
请参阅System.Text.Json的答案:How do I indicates a custom name for an enum value? 寻找潜在的解决方法。
杰森.NET:
一个第三方库,可用于在 ASP.NET Core 3.0+ 中序列化,方法是添加 NuGet 引用,Microsoft.AspNetCore.Mvc.NewtonsoftJson然后AddNewtonsoftJson()在Startup.ConfigureServices.
有关详细信息,请参阅此答案:Where did IMvcBuilder AddJsonOptions go in .Net Core 3.0? 被戳。
命名空间包括Newtonsoft.Json、Newtonsoft.Json.Converters、Newtonsoft.Json.Linq等。Newtonsoft.Json.Serialization
类包括Newtonsoft.Json.JsonConverter,Newtonsoft.Json.JsonConverter<T>和Newtonsoft.Json.JsonSerializer
属性包括Newtonsoft.Json.JsonPropertyAttribute、Newtonsoft.Json.JsonConverterAttribute等。Newtonsoft.Json.JsonExtensionDataAttribute
应用属性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; }
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,您将 Newtonsoft 的属性与 的转换器混合在一起System.Text.Json,这是行不通的。(也许您通过 Visual Studio 中的“解析 -> 使用...”右键单击选择了命名空间?)
那么,如何解决这个问题呢?由于 Json.NET 支持开箱即用地重命名枚举值,因此解决问题的最简单方法是使用此序列化器。虽然性能可能不如它,但System.Text.Json它更加完整和功能齐全。
为此,请从代码中删除命名空间System.Text.Json.Serialization和System.Text.Json以及对该类型的引用,并按如下方式修改和:JsonStringEnumConverterMyRequestBoardSymbols
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 = '?'
}
}
Run Code Online (Sandbox Code Playgroud)
然后 NuGetMicrosoft.AspNetCore.Mvc.NewtonsoftJson并Startup.ConfigureServices调用AddNewtonsoftJson():
services.AddMvc()
.AddNewtonsoftJson();
Run Code Online (Sandbox Code Playgroud)
或者,如果您更喜欢全局使用StringEnumConverter:
services.AddMvc()
.AddNewtonsoftJson(o => o.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()));
Run Code Online (Sandbox Code Playgroud)
请注意文档中的以下评论
注意:如果该
AddNewtonsoftJson方法不可用,请确保安装了Microsoft.AspNetCore.Mvc.NewtonsoftJson包。一个常见错误是安装Newtonsoft.Json包而不是Microsoft.AspNetCore.Mvc.NewtonsoftJson包。
样机小提琴在这里。
| 归档时间: |
|
| 查看次数: |
10946 次 |
| 最近记录: |