8

I have simple DTO

public class SimpleDto
{
    public int Status { get; set; }
    public long FromDate { get; set; }
    public long ToDate { get; set; }
}

And I have ProxyDto with TypeConverterAttribute:

[TypeConverter(typeof(SimpleConvert<SimpleDto>))]
public class ProxyDto<T>
{
    public T Object { get; set; }
}

Here is the implementation of SimpleConvert:

public class SimpleConvert<T> : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) ||
                base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        var strValue = value as string;
        return strValue != null
            ? new ProxyDto<T>{ Object = JsonConvert.DeserializeObject<T>(strValue)}
            : base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        var val = value as ProxyDto<T>;
        return destinationType == typeof(string) && val != null ? val.Object.ToJson() : base.ConvertTo(context, culture, value, destinationType);
    }
}

Also I have simple Json for DTO:

{"Status":3,"FromDate":12345,"ToDate":54321}

When I try to deserialize this object via proxy

var obj = JsonConvert.DeserializeObject<ProxyDto<SimpleDto>>(str);

it fails with Exception 'Newtonsoft.Json.JsonSerializationException'

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'Detect_Console_Application_Exit2.ProxyDto`1[Detect_Console_Application_Exit2.SimpleDto]' because the type requires a JSON string value to deserialize correctly. To fix this error either change the JSON to a JSON string value or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. Path 'Status', line 1, position 10.

But if my Json has escaping Json:

"{\"Status\":3,\"FromDate\":12345,\"ToDate\":54321}"

it works well. I don't understand why the first JSON object is not correct. Can you help me?

Update

Here is ToJson method:

public static class Extension
{
    public static string ToJson(this object val)
    {
        return JsonConvert.SerializeObject(val);
    }
}
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
Maxim Goncharuk
  • 1,285
  • 12
  • 20
  • @CodeCaster I've updated my question. – Maxim Goncharuk Dec 04 '15 at 13:23
  • @maxim `SimpleDto obj = JsonConvert.DeserializeObject(jsonstring);` As the error message say you can't deserialize a single object into a collection (ProxyDto<>). – Krsna Kishore Dec 04 '15 at 13:28
  • @Webruster `ProxyDto` is not a collection. – CodeCaster Dec 04 '15 at 13:35
  • Can you put a breakpoint in `ConvertFrom()` and inspect `value`? Chances are it's not a string. – CodeCaster Dec 04 '15 at 13:37
  • Where is the `ToJson` method you're using in `ConvertTo`? – Yuval Itzchakov Dec 04 '15 at 13:39
  • @CodeCaster `value` is a string look like the first JSON object. – Maxim Goncharuk Dec 04 '15 at 13:44
  • 1
    Out of curiosity, why are you even using a `TypeConverter` with your `ProxyDto`? If your goal is to convert the proxy to/from JSON, you can just call `JsonConvert.SerializeObject()` / `JsonConvert.DeserializeObject()` on the proxy and it should work fine without the converter. The converter is forcing it to be double serialized, which is why you end up with the escaped JSON. – Brian Rogers Dec 04 '15 at 15:57
  • 1
    I try to parse query string from GET method in WCF server, so it has to have TypeConvertAttribute. But I cannot do it, because JsonConverter also use this attribute and I create proxy object for encapsulating `SimleDto`. – Maxim Goncharuk Dec 04 '15 at 15:59
  • 1
    Json.NET sees that your `ProxyDto` has a `TypeConverter` and uses that to convert it from and to a string. See [Serialization Guide](http://www.newtonsoft.com/json/help/html/SerializationGuide.htm). To avoid this, use the solution from [Newtonsoft.JSON cannot convert model with TypeConverter attribute](https://stackoverflow.com/questions/31325866). – dbc Dec 04 '15 at 16:23
  • 1
    @dbc It seems to be work. Thank you. – Maxim Goncharuk Dec 04 '15 at 16:26

1 Answers1

0

As @dbc said it just convert objects that inherit from JsonConverter, below is the code that they use, the default serializer is based on the converters parameter. You should inherit from JsonConverter instead of TypeConverter

public static object DeserializeObject(string value, Type type, params JsonConverter[] converters)
{
  JsonSerializerSettings serializerSettings;
  if (converters == null || converters.Length <= 0)
    serializerSettings = (JsonSerializerSettings) null;
  else
    serializerSettings = new JsonSerializerSettings()
    {
      Converters = (IList<JsonConverter>) converters
    };
  JsonSerializerSettings settings = serializerSettings;
  return JsonConvert.DeserializeObject(value, type, settings);
}

public static object DeserializeObject(string value, Type type, JsonSerializerSettings settings)
{
  ValidationUtils.ArgumentNotNull((object) value, "value");
  JsonSerializer @default = JsonSerializer.CreateDefault(settings);
  if (!@default.IsCheckAdditionalContentSet())
    @default.CheckAdditionalContent = true;
  using (JsonTextReader jsonTextReader = new JsonTextReader((TextReader) new StringReader(value)))
    return @default.Deserialize((JsonReader) jsonTextReader, type);
}
Zinov
  • 3,817
  • 5
  • 36
  • 70