Десериализация JSON с использованием JsonSerializer.DeserializeAsync не использует мой JsonConverter - PullRequest
4 голосов
/ 03 октября 2019

Сервер возвращает строковое значение JSON, которое является строкой URL-запроса:

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

У меня есть свойство, настроенное для получения этого, и преобразования его в Dictionary как часть десериализацииprocess:

Свойство с атрибутом 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) просто использовать мой конвертер, не пытаясь быть умным сам по себе?

(я использую Microsoft System.Text.Json в .NETCore 3)

Ответы [ 2 ]

0 голосов
/ 03 октября 2019

Я бы создал оболочку и конвертер для оболочки.

[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 голосов
/ 03 октября 2019

ОК, так что это может быть ошибка в System.Text.Json.

Вот обходной путь, который я в настоящее время использую для всех, кому нужно решение.

Сначала я установил два свойствадля десериализации, используя [JsonPropertyName] и [JsonIgnore]:

[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, которое будет продолжать нормально работать, если и когда эта ошибка будет исправлена, и я вернусь к классу так, как мне хотелось бы.

...