列挙型の使用:
_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にシリアル化する必要があります。このアプローチは json文字を列挙型としてデシリアライズする から採用されています。ただし、機能しません。これは、列挙型を次のように変更した場合に機能します。
_ [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が必要です。
TL/DR:ここに2つの基本的な問題があります。
.NET Core 3.0+には 新しい組み込みJSONシリアライザーSystem.Text.Json
があり、この新しいシリアライザーと の間で属性とクラスを混同しています/Json.NET 。これらは、JsonSerializer
やJsonConverter
などのいくつかのクラス名を共有しているため、両方をインストールすると非常に簡単に実行できます。
新しいシリアライザーがデフォルトで使用されますが、カスタム値の名前を持つ文字列としての列挙型のシリアライズはまだサポートされていません。 System.Text.Json:enum値にカスタム名を指定するにはどうすればよいですか?を参照してください。
問題を解決する最も簡単な方法は、 here のようにJson.NETに切り替えて、このシリアライザーからの属性、コンバーター、名前空間のみを使用することです。
最初に、2つのシリアライザーの違いと類似点を分析します。
System.Text.Json
:
.NET Core 3.0+に自動的に組み込まれ、ASP.NET Core 3.0+によるJSONシリアル化に使用されます デフォルトで 。
名前空間 System.Text.Json
および System.Text.Json.Serialization
。
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 to System.Text.Json:enum値にカスタム名を指定するにはどうすればよいですかを参照してください?潜在的な回避策。
Json.NET:
Nusome参照をMicrosoft.AspNetCore.Mvc.NewtonsoftJson
に追加してStartup.ConfigureServices
で AddNewtonsoftJson()
を呼び出すことにより、ASP.NET Core 3.0+でのシリアル化に使用できるサードパーティライブラリ。
詳細については、 this answer to IMvcBuilder AddJsonOptionsが.Net Core 3.0でどこに移動したかを参照してください。 by 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 。
名前が変更された文字列としての列挙型のシリアル化は、 EnumMemberAttribute
属性が適用されると、 Newtonsoft.Json.Converters.StringEnumConverter
によって自動的にサポートされます。
これを念頭に置いて、コードでどのシリアライザを使用していますか?質問に参考にして名前空間を含めたので、次のことを確認できます。
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
をremoveし、コードから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 パッケージ。一般的なエラーは、 Microsoft.AspNetCore.Mvc.NewtonsoftJson パッケージの代わりに Newtonsoft.Json パッケージをインストールすることです。
モックアップのフィドル here 。