サーバーが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を使用しています)
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
プロパティを使用するだけで、このバグが修正されたときに問題なく機能し、クラスを希望どおりに変更します。
ラッパーを作成し、ラッパーのコンバーターを作成します。
[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>
プロパティ、意図しない可能性があります。元の質問の簡単な例では問題なく機能します。