0

I have a simple object that my API returns

{
"Code":0,
"Message":"String",
"Data":"Can Be Anything"
}

Data can be string or any other object like Person, Cat, List etc...

I mapped the response to c# putting Data as Object, lets say I called this object "Response"

I would like to know if is possible when I deserialize I inform the type that Data will be and make a converert to understand and cast Data to the type I´ve passed.

Would be something like

public static Response ToWrapper<T>(this string json)
{
    return JsonConvert.DeserializeObject<Response>(json, new Converter<T>());
}

In this example I would say that Data is a dummy class called Person with props string Name, string Email and int Age, so the response would be

string json = "
{
   "Code":1,
   "Message":"OK",
   "Data": {"Name": "Patrick", "Email": "aa@aaa.com", "Age" : 25}
}"

So in some point of my code I would

var ResponseWrapper = json.ToWrapper<Person>();

string personName = ResponseWrapper.Data.Name;  
string personEmail = ResponseWrapper.Data.Email;
int personAge = ResponseWrapper.Data.Age; //<----- NO CAST NEEDED

The converter would transform object Data to Person Data!!!

The converter I tried some code with no sucess! I tried a lot of codes and the close that I could get was with this from here How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?

public class PersonConverter<T> : JsonCreationConverter<T>
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

        protected override T Create(Type objectType, JObject jObject)
        {
            T obj = Activator.CreateInstance<T>();

            if (FieldExists("Data", jObject))
            {
                return obj;
            }
            else
                return obj;
        }

        private bool FieldExists(string fieldName, JObject jObject)
        {
            return jObject[fieldName] != null;
        }
    }

    public abstract class JsonCreationConverter<T> : JsonConverter
    {
        /// <summary>
        /// Create an instance of objectType, based properties in the JSON object
        /// </summary>
        /// <param name="objectType">type of object expected</param>
        /// <param name="jObject">
        /// contents of JSON object that will be deserialized
        /// </param>
        /// <returns></returns>
        protected abstract T Create(Type objectType, JObject jObject);

        public override bool CanConvert(Type objectType)
        {
            return true; // typeof(T).IsAssignableFrom(objectType);
        }

        public override bool CanWrite
        {
            get { return false; }
        }

        public override object ReadJson(JsonReader reader,
                                        Type objectType,
                                         object existingValue,
                                         JsonSerializer serializer)
        {
            // Load JObject from stream
            JObject jObject = JObject.Load(reader);

            // Create target object based on JObject
            T target = Create(objectType, jObject);

            // Populate the object properties
            serializer.Populate(jObject.CreateReader(), target);

            return target;
        }
    }
2Fast4YouBR
  • 1,012
  • 1
  • 12
  • 22

1 Answers1

2

I think the best path forward is to use offload the deserialization of the Code and Message to a JObject, and then use JsonConvert to deserialize the data object.

https://dotnetfiddle.net/bP2Ew6

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public class Program
{
    public static void Main()
    {
        string json = @"
            {
               ""Code"":1,
               ""Message"":""OK"",
               ""Data"": {""Name"": ""Patrick"", ""Email"": ""aa@aaa.com"", ""Age"" : 25}
            }";

        Console.WriteLine(json);

        var response=json.ToWrapper<Person>();

        Console.WriteLine("Name: "+response.Data.Name);
        Console.WriteLine("Email: "+response.Data.Email);
        Console.WriteLine("Age: "+response.Data.Age);
    }
}

public class Person{
    public string Name {get;set;}
    public string Email {get;set;}
    public int Age {get;set;}
}

public class Response<T>{
    public int Code {get;set;}
    public string Message {get;set;}
    public T Data {get;set;}
}

public static class ResponseExtensions {
    public static Response<T> ToWrapper<T>(this string json){

        var o=JObject.Parse(json);
        var data=JsonConvert.DeserializeObject<T>(o["Data"].ToString());

        return new Response<T>{
            Code=(int)o["Code"],
            Message=(string)o["Message"],
            Data=data
        };
    }
}
Kaizen Programmer
  • 3,798
  • 1
  • 14
  • 30
  • Michael, it´s working fine for complex objects (person or any custom class).. the Problem now is with plain objects like string, int, float... because the data wont be a json string it will be just the plain object result.. https://dotnetfiddle.net/QDOUQn To fix that I would have just to compare T if is string, int, so would not be needed to deserialize once the object is allready the value that I want. My question now is if this is the best way to wotk with plain objects... cheers!!!! – 2Fast4YouBR Mar 02 '18 at 14:54
  • Have you tried using `.ToWrapper()`, `.ToWrapper()`, `.ToWrapper()` – Kaizen Programmer Mar 02 '18 at 20:12
  • doesn't work... my dal/service for simple things only returns the plain object and the JsonConvert wants a json (string with json like {"x" : "WYZ"}) so it can deserialize... I solved putting an IF and checking typeof(T) == typeof(string) so its just cast like (string)o["Data"] not passing to JsonConvert.DeserializeObject.... thanks!! – 2Fast4YouBR Mar 03 '18 at 00:36