0

I am using the new .NET serialization classes from System.Text.Json to deserialize a JSON response from a restful endpoint. The structure of the response is:

public class RemoteCallResultDto
{
    public bool Succeeded { get; set; }
    public string Message { get; set; }
}

public class RemoteCallResultDto<T> : RemoteCallResultDto
{
    public T Payload { get; set; }
}

The generic type is what i want to deserialize. The Payload could be a primitive or a class. So i created a custom converter as outlined here.

My converter is as follows:

public class RemoteCallResultDtoTConverter : JsonConverterFactory
{
    public override bool CanConvert(Type typeToConvert)
    {
        return typeToConvert.IsGenericType &&
                typeToConvert.GetGenericTypeDefinition() == typeof(RemoteCallResultDto<>);
    }

    public override JsonConverter CreateConverter(Type type, JsonSerializerOptions options)
    {
        Type valueType = type.GetGenericArguments()[0];

        JsonConverter converter = (JsonConverter)Activator.CreateInstance(
            typeof(RemoteCallResultDtoConverterInner<>).MakeGenericType(
                new Type[] { valueType }),
            BindingFlags.Instance | BindingFlags.Public,
            binder: null,
            args: new object[] { options },
            culture: null);

        return converter;
    }

    private class RemoteCallResultDtoConverterInner<TPayloadType> : JsonConverter<RemoteCallResultDto<TPayloadType>>
    {
        private readonly JsonConverter<TPayloadType> _valueConverter;

        public RemoteCallResultDtoConverterInner(JsonSerializerOptions options)
        {
            // For performance, use the existing converter if available.
            _valueConverter = (JsonConverter<TPayloadType>)options
                .GetConverter(typeof(TPayloadType));
        }

        public override RemoteCallResultDto<TPayloadType> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (_valueConverter != null)
                return new RemoteCallResultDto<TPayloadType> { Payload = _valueConverter.Read(ref reader, typeToConvert, options) };
            else
                throw new JsonException();
        }

        public override void Write(Utf8JsonWriter writer, RemoteCallResultDto<TPayloadType> value, JsonSerializerOptions options)
        {
            if (_valueConverter != null)
                _valueConverter.Write(writer, value.Payload, options);
            else
                throw new JsonException();
        }
    }
}

My problem is that the _valueConverter in the RemoteCallResultDtoConverterInner constructor is always null. This is how i attempt to do the deserialization:

 var serializerOptions = new JsonSerializerOptions();
        serializerOptions.Converters.Add(new RemoteCallResultDtoTConverter());

        RemoteCallResultDto<K> res = JsonSerializer.Deserialize<RemoteCallResultDto<K>>(response, serializerOptions);

Where the response is valid JSON of the form:

{"payload":{"email":"arlvinm@yahoo.com","firstName":"Arlvin","lastName":"Moyo","organization":"Aquants","permissions":["User management - View","Lookup data - View"]},"succeeded":true,"message":null}

Where am i going wrong?

arlvin
  • 379
  • 1
  • 4
  • 11
  • 2
    You don't need a converter, only the right NamingPolicy. Use `serializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;` instead of your converter – Kalten Nov 23 '20 at 21:03
  • 1
    1) Your code doesn't compile because the type `K` is not found. See https://dotnetfiddle.net/QPguzA. 2) Why do you need a converter at all? This converter looks like it's trying to handle polymorphism, but the type to which to deserialize, `RemoteCallResultDto`, is fully defined. What is the converter trying to do? – dbc Nov 23 '20 at 21:30
  • 3) As shown in the [Sample factory pattern converter](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to?pivots=dotnet-5-0#sample-factory-pattern-converter), `_valueConverter` might be null, in which case you should call `JsonSerializer.Deserialize(ref reader, options)` – dbc Nov 23 '20 at 21:30
  • @Kalten, thanks. Your comment was actually the answer, i.e. setting the PropertyNamingPolicy. You were right, i don't need a converter. I've up-voted your comment. I suppose because it's just a comment i couldn't mark it as the answer, which it is. To user dbc, I wasn't getting results so i thought perhaps i needed a converter. Am still learning all this. If you can point me to an article that explains when one needs a converter i'd appreciate it. – arlvin Nov 24 '20 at 08:30

0 Answers0