web-dev-qa-db-ja.com

列挙型の配列でjsonをデシリアライズします

列挙型の使用:

_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'
    }
_

しかし、私は明らかに「空の」列挙の限界に達しました。これどうやってするの?

アップデート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が必要です。

3
roberto tomás

TL/DR:ここに2つの基本的な問題があります。

  1. .NET Core 3.0+には 新しい組み込みJSONシリアライザーSystem.Text.Json があり、この新しいシリアライザーと の間で属性とクラスを混同しています/Json.NET 。これらは、JsonSerializerJsonConverterなどのいくつかのクラス名を共有しているため、両方をインストールすると非常に簡単に実行できます。

  2. 新しいシリアライザーがデフォルトで使用されますが、カスタム値の名前を持つ文字列としての列挙型のシリアライズはまだサポートされていません。 System.Text.Json:enum値にカスタム名を指定するにはどうすればよいですか?を参照してください。

問題を解決する最も簡単な方法は、 here のようにJson.NETに切り替えて、このシリアライザーからの属性、コンバーター、名前空間のみを使用することです。

最初に、2つのシリアライザーの違いと類似点を分析します。

  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.Jsonremoveし、コードから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 パッケージ。一般的なエラーは、 Microsoft.AspNetCore.Mvc.NewtonsoftJson パッケージの代わりに Newtonsoft.Json パッケージをインストールすることです。

モックアップのフィドル here

0
dbc