Reputation: 1042
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": "[email protected]", "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;
}
}
Upvotes: 1
Views: 4686
Reputation: 3818
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"": ""[email protected]"", ""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
};
}
}
Upvotes: 4