web-dev-qa-db-ja.com

JsonSerializer.DeserializeAsyncを使用してJSONをデシリアライズするとJsonConverterが使用されない

サーバーがURLクエリ文字列であるJSON文字列値を返しています:

_{
    "parameters": "key1=value1&key2=value2"
}
_

これを受け取るようにプロパティを設定し、逆シリアル化プロセスの一部としてDictionaryに変換します。

JsonConverter属性を持つプロパティ:

_[JsonConverter(typeof(QueryStringToDictionaryJsonConverter))]
public Dictionary<string, string> Parameters { get; set; }
_

コンバータ:

_public class QueryStringToDictionaryJsonConverter : JsonConverter<Dictionary<string, string>> {

    public override Dictionary<string, string> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {

        var queryString = reader.GetString();
        if (string.IsNullOrEmpty(queryString)) return null;

        return QueryHelpers.ParseQuery(queryString).ToDictionary(e => e.Key, e => string.Join(",", e.Value.ToArray()));

    }

    ...
}
_

これはうまくいくはずです。

しかし、それも私のコンバーターに到達していません。

私が知ることができることから、JsonSerializer.DeserializeAsync<T>(myJson)はプロパティのタイプがDictionaryであることを認識しているため、それ自体で値を解析しようとし、失敗します(結果の例外はGetEnumerable()など)を試みる「無効なキャスト」。コンバーターのブレークポイントがヒットすることはありません。

プロパティをobjectにし、後でDictionaryにキャストして使用することで機能させることができますが、これは醜い解決策です。

JsonSerializer.DeserializeAsync<T>(myJson)が自分自身を賢くしようとせずに、コンバーターを使用するように強制する方法はありますか?

(私は.NET Core 3でMicrosoftのSystem.Text.Jsonを使用しています)

4
Ross

OK、これはSystem.Text.Jsonのバグである可能性があります。

これは、ソリューションを必要とする他の人のために私が現在使用している回避策です。

まず、[JsonPropertyName][JsonIgnore]を使用して、逆シリアル化の2つのプロパティを設定します。

[JsonPropertyName("parameters"), JsonConverter(typeof(QueryStringToDictionaryJsonConverter))]
public object ParametersObject { get; set; }

[JsonIgnore]
public Dictionary<string, string> Parameters => ParametersObject as Dictionary<string, string>;

そして、JsonConverterでは、タイプとしてobjectを許可します。

public override bool CanConvert(Type typeToConvert) {
    if (typeToConvert == typeof(object)) return true;
    return base.CanConvert(typeToConvert);
}

逆シリアル化されたクラスのコンシューマーはParametersプロパティを使用するだけで、このバグが修正されたときに問題なく機能し、クラスを希望どおりに変更します。

0
Ross

ラッパーを作成し、ラッパーのコンバーターを作成します。

[JsonConverter( typeof( QueryStringDictionaryConverter ) )]
class QueryStringDictionary : Dictionary<string,string> { }

class QueryStringDictionaryConverter : JsonConverter<QueryStringDictionary>
{
    ... 
}

class MyClass
{
    public QueryStringDictionary Parameters { get; set; }
}

または、JsonSerializerOptionsを使用することもできます

class MyOtherClass
{
   public Dictionary<string,string> Parameters { get; set; }
}
MyOtherClass Deserialize( string json )
{
    var options = new JsonSerializerOptions
    {
        Converters = { new QueryStringToDictionaryJsonConverter() }
    };
    return JsonSerializer.Deserialize<MyOtherClass>( json, options );  
} 

このアプローチの潜在的な問題は、コンバーターがすべてのDictionary<string,string>プロパティ、意図しない可能性があります。元の質問の簡単な例では問題なく機能します。

0
phizch