Given this JSON,
{
"token": {
"accessToken": "scrciFyGuLAQn6XgKkaBWOxdZA1",
"issuedAt": "2022-11-06T22:54:27Z",
"expiresIn": 1799
}
}
I can get the DeserializeObject
to work if I define the model as this
public class Root
{
public Token Token { get; set; }
}
public class Token
{
public string AccessToken { get; set; }
public DateTime IssuedAt { get; set; }
public int ExpiresIn { get; set; }
}
And use this call:
Root myRoot = JsonConvert.DeserializeObject<Root>(apiResponse);
The third-party API I am calling has all methods returning a similar JSON response, in that it has a header object containing a single object of a specific type, such as:
{
"user": {
"preferences": {},
"address": {},
"name": {},
"email": "string",
"segmentName": "string"
}
}
which requires a model looking like this:
public class Address
{
}
public class Name
{
}
public class Preferences
{
}
public class Root
{
public User user { get; set; }
}
public class User
{
public Preferences preferences { get; set; }
public Address address { get; set; }
public Name name { get; set; }
public string email { get; set; }
public string segmentName { get; set; }
}
I do not want to be having to define a different Root
class for every one of the JSON responses. Is there a way to avoid this?
CodePudding user response:
I would argue that defining Root
objects is better approach cause it makes expected json structure defined explicitly but if you want you can use Newtonsoft's LINQ API via JObject
(docs):
var jObject = JObject.Parse(json);
var user = jObject["user"].ToObject<User>();
Similar can be done via JsonNode API for System.Text.Json
(available starting .NET 6).
CodePudding user response:
One way to solve it by having a wrapper defining all possible "content" names as properties. Then having one property to return the value which is populated after de-serialization.
public class Response<T>
{
public User User { get; set; }
public Token Token { get; set; }
public Token AuthToken { get; set; }
public XYZ XYZ { get; set; }
public T Content => GetType().GetProperties().Where(p => p.Name != nameof(Content)).Select(p => p.GetValue(this)).Single(v => v != null) as T;
}
Then, just having a method for deserializing like this
public T DeserializeResponse<T>(string json)
{
return Deserialize<Response<T>>(json).Content;
}
There is also a more dynamic way possible, if there are too many different contents you need to retrieve, but that would require overriding some more reflection and going deeper into deserialization process.