I am writing tests for my controllers (ASP.NET Core), and am receiving back some JSON. I would now like to deserialize it into the correct object so that I can do some assertions against the returned data. There are no exceptions thrown during deserialization, but my Data variable is null.
Here is the code used for the deserialization:
var output = JsonConvert.DeserializeObject(responseString,
typeof(CrudOperationResult<IEnumerable<ApiResource>>));
This is the CrudOperationResult class:
public class CrudOperationResult<T>
{
private CrudOperationResult()
{ }
private CrudOperationResult(CrudResult result, string errorMessage, T data)
{
Result = result;
ErrorMessage = errorMessage;
Data = data;
}
[JsonIgnore]
public CrudResult Result { get; private set; }
public bool IsError
{
get
{
return Result == CrudResult.Error;
}
}
public string ErrorMessage { get; private set; }
public T Data { get; private set; }
}
And here is the JSON data returned:
{
"isError": false,
"errorMessage": null,
"data": [{
"id": 1,
"enabled": true,
"name": "apiResource1",
"displayName": "My API",
"description": null,
"secrets": null,
"scopes": [{
"id": 1,
"name": "apiResource1",
"displayName": "My API",
"description": null,
"required": false,
"emphasize": false,
"showInDiscoveryDocument": true,
"userClaims": null
}],
"userClaims": [{
"id": 1,
"type": "role"
},
{
"id": 2,
"type": "user"
}]
}]
}
Because of the [...] JsonConvert.DeserializeObject thinks data a List<T> Data { get; private set; }.
Issue 1: To deserialize JSON, you need a public constructor with no arguments.
Issue 2: You can't deserialize an interface type (IEnumerable).
Try:
var output = JsonConvert.DeserializeObject(responseString,
typeof(CrudOperationResult<List<ApiResource>>));
use this function :
List<T> ToJson<T>(byte[] byteArray) where T : new()
{
MemoryStream stream = new MemoryStream(byteArray);
JsonSerializer se = new JsonSerializer();
StreamReader re = new StreamReader(stream);
JsonTextReader reader = new JsonTextReader(re);
return se.Deserialize<List<T>>(reader);
}
Related
I have this JSON:
[
{
"Attributes": [
{
"Key": "Name",
"Value": {
"Value": "Acc 1",
"Values": [
"Acc 1"
]
}
},
{
"Key": "Id",
"Value": {
"Value": "1",
"Values": [
"1"
]
}
}
],
"Name": "account",
"Id": "1"
},
{
"Attributes": [
{
"Key": "Name",
"Value": {
"Value": "Acc 2",
"Values": [
"Acc 2"
]
}
},
{
"Key": "Id",
"Value": {
"Value": "2",
"Values": [
"2"
]
}
}
],
"Name": "account",
"Id": "2"
},
{
"Attributes": [
{
"Key": "Name",
"Value": {
"Value": "Acc 3",
"Values": [
"Acc 3"
]
}
},
{
"Key": "Id",
"Value": {
"Value": "3",
"Values": [
"3"
]
}
}
],
"Name": "account",
"Id": "2"
}
]
And I have these classes:
public class RetrieveMultipleResponse
{
public List<Attribute> Attributes { get; set; }
public string Name { get; set; }
public string Id { get; set; }
}
public class Value
{
[JsonProperty("Value")]
public string value { get; set; }
public List<string> Values { get; set; }
}
public class Attribute
{
public string Key { get; set; }
public Value Value { get; set; }
}
I am trying to deserialize the above JSON using the code below:
var objResponse1 = JsonConvert.DeserializeObject<RetrieveMultipleResponse>(JsonStr);
but I am getting this error:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type
'test.Model.RetrieveMultipleResponse' because the type requires a JSON
object (e.g. {"name":"value"}) to deserialize correctly. To fix this
error either change the JSON to a JSON object (e.g. {"name":"value"})
or change the deserialized type to an array or a type that implements
a collection interface (e.g. ICollection, IList) like List that can
be deserialized from a JSON array. JsonArrayAttribute can also be
added to the type to force it to deserialize from a JSON array. Path
'', line 1, position 1.
Your json string is wrapped within square brackets ([]), hence it is interpreted as array instead of single RetrieveMultipleResponse object. Therefore, you need to deserialize it to type collection of RetrieveMultipleResponse, for example :
var objResponse1 =
JsonConvert.DeserializeObject<List<RetrieveMultipleResponse>>(JsonStr);
If one wants to support Generics (in an extension method) this is the pattern...
public static List<T> Deserialize<T>(this string SerializedJSONString)
{
var stuff = JsonConvert.DeserializeObject<List<T>>(SerializedJSONString);
return stuff;
}
It is used like this:
var rc = new MyHttpClient(URL);
//This response is the JSON Array (see posts above)
var response = rc.SendRequest();
var data = response.Deserialize<MyClassType>();
MyClassType looks like this (must match name value pairs of JSON array)
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class MyClassType
{
[JsonProperty(PropertyName = "Id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "Description")]
public string Description { get; set; }
[JsonProperty(PropertyName = "Manager")]
public string Manager { get; set; }
[JsonProperty(PropertyName = "LastUpdate")]
public DateTime LastUpdate { get; set; }
}
Use NUGET to download Newtonsoft.Json add a reference where needed...
using Newtonsoft.Json;
Can't add a comment to the solution but that didn't work for me. The solution that worked for me was to use:
var des = (MyClass)Newtonsoft.Json.JsonConvert.DeserializeObject(response, typeof(MyClass));
return des.data.Count.ToString();
Deserializing JSON array into strongly typed .NET object
Use this, FrontData is JSON string:
var objResponse1 = JsonConvert.DeserializeObject<List<DataTransfer>>(FrontData);
and extract list:
var a = objResponse1[0];
var b = a.CustomerData;
To extract the first element (Key) try this method and it will be the same for the others :
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.GetAsync("Your URL"))
{
var apiResponse = await response.Content.ReadAsStringAsync();
var list = JObject.Parse(apiResponse)["Attributes"].Select(el => new { Key= (string)el["Key"] }).ToList();
var Keys= list.Select(p => p.Key).ToList();
}
}
var objResponse1 =
JsonConvert.DeserializeObject<List<RetrieveMultipleResponse>>(JsonStr);
worked!
I am having trouble deserializing JSON received from HubSpot ContactList API.
I am using Restsharp and NewtonSoft, and I'm having real struggles understanding how to correctly define the required classes in order to deserialize the JSON string, which is below:
"contacts": [
{
"vid": 2251,
"portal-id": 5532227,
"is-contact": true,
"profile-url": "https://app.hubspot.com/contacts/5532227/contact/2251",
"properties": {
"firstname": {
"value": "Carl"
},
"lastmodifieddate": {
"value": "1554898386040"
},
"company": {
"value": "Cygnus Project"
},
"lastname": {
"value": "Swann"
}
},
"form-submissions": [],
"identity-profiles": [
{
"vid": 2251,
"saved-at-timestamp": 1553635648634,
"deleted-changed-timestamp": 0,
"identities": [
{
"type": "EMAIL",
"value": "cswann#cygnus.co.uk",
"timestamp": 1553635648591,
"is-primary": true
},
{
"type": "LEAD_GUID",
"value": "e2345",
"timestamp": 1553635648630
}
]
}
],
"merge-audits": []
},
{
"vid": 2301,
"portal-id": 5532227,
"is-contact": true,
"profile-url": "https://app.hubspot.com/contacts/5532227/contact/2301",
"properties": {
"firstname": {
"value": "Carlos"
},
"lastmodifieddate": {
"value": "1554886333954"
},
"company": {
"value": "Khaos Control"
},
"lastname": {
"value": "Swannington"
}
},
"identity-profiles": [
{
"vid": 2301,
"saved-at-timestamp": 1553635648733,
"deleted-changed-timestamp": 0,
"identities": [
{
"type": "EMAIL",
"value": "cswann#khaoscontrol.com",
"timestamp": 1553635648578,
"is-primary": true
},
{
"type": "LEAD_GUID",
"value": "c7f403ba",
"timestamp": 1553635648729
}
]
}
],
"merge-audits": []
}
],
"has-more": false,
"vid-offset": 2401
}
If I simply request the vid, I correctly get 2 vid's back. It's when I try to do the properties and that i get a fail.
Please help
Lets reduce the Json to the minimum to reproduce your error :
{
"vid": 2301,
"portal-id": 5532227,
"is-contact": true,
"profile-url": "https://app.hubspot.com/contacts/5532227/contact/2301",
"properties": {
"firstname": {
"value": "Carlos"
},
"lastmodifieddate": {
"value": "1554886333954"
},
"company": {
"value": "Khaos Control"
},
"lastname": {
"value": "Swannington"
}
}
}
And the appropriate class ContactListAPI_Result:
public partial class ContactListAPI_Result
{
[JsonProperty("vid")]
public long Vid { get; set; }
[JsonProperty("portal-id")]
public long PortalId { get; set; }
[JsonProperty("is-contact")]
public bool IsContact { get; set; }
[JsonProperty("profile-url")]
public Uri ProfileUrl { get; set; }
[JsonProperty("properties")]
public Dictionary<string, Dictionary<string, string>> Properties { get; set; }
}
public partial class ContactListAPI_Result
{
public static ContactListAPI_Result FromJson(string json)
=> JsonConvert.DeserializeObject<ContactListAPI_Result>(json);
//public static ContactListAPI_Result FromJson(string json)
// => JsonConvert.DeserializeObject<ContactListAPI_Result>(json, Converter.Settings);
}
public static void toto()
{
string input = #" {
""vid"": 2301,
""portal-id"": 5532227,
""is-contact"": true,
""profile-url"": ""https://app.hubspot.com/contacts/5532227/contact/2301"",
""properties"": {
""firstname"": {
""value"": ""Carlos""
},
""lastmodifieddate"": {
""value"": ""1554886333954""
},
""company"": {
""value"": ""Khaos Control""
},
""lastname"": {
""value"": ""Swannington""
}
}
}";
var foo = ContactListAPI_Result.FromJson(input);
}
But the Value of one property will be burrow in the sub dictionary, we can the project the object in a more usefull one :
public partial class ItemDTO
{
public long Vid { get; set; }
public long PortalId { get; set; }
public bool IsContact { get; set; }
public Uri ProfileUrl { get; set; }
public Dictionary<string, string> Properties { get; set; }
}
Adding the projection to the Class:
public ItemDTO ToDTO()
{
return new ItemDTO
{
Vid = Vid,
PortalId = PortalId,
IsContact = IsContact,
ProfileUrl = ProfileUrl,
Properties =
Properties.ToDictionary(
p => p.Key,
p => p.Value["value"]
)
};
}
Usage :
var result = foo.ToDTO();
Live Demo
Creating and managing class structure for big and nested key/value pair json is tedious task
So one approach is to use JToken instead.
You can simply parse your JSON to JToken and by querying parsed object, you will easily read the data that you want without creating class structure for your json
From your post it seems you need to retrieve vid and properties from your json so try below code,
string json = "Your json here";
JToken jToken = JToken.Parse(json);
var result = jToken["contacts"].ToObject<JArray>()
.Select(x => new
{
vid = Convert.ToInt32(x["vid"]),
properties = x["properties"].ToObject<Dictionary<string, JToken>>()
.Select(y => new
{
Key = y.Key,
Value = y.Value["value"].ToString()
}).ToList()
}).ToList();
//-----------Print the result to console------------
foreach (var item in result)
{
Console.WriteLine(item.vid);
foreach (var prop in item.properties)
{
Console.WriteLine(prop.Key + " - " + prop.Value);
}
Console.WriteLine();
}
Output:
I have an MVC application, that serializes my model into json schema (using Newtonsoft json.net schema). The problem is that items in my array have type ["string", "null"], but what I need is just "string". Here is code for my class:
public class Form
{
[Required()]
public string[] someStrings { get; set; }
}
This is schema made by Json.net schema:
"someStrings": {
"type": "array",
"items": {
"type": [
"string",
"null"
]
}
}
While I am expecting this:
"someStrings": {
"type": "array",
"items": {
"type": "string"
}
}
Help me get rid of that "null" please.
Try setting DefaultRequired to DisallowNull when you generate the schema:
JSchemaGenerator generator = new JSchemaGenerator()
{
DefaultRequired = Required.DisallowNull
};
JSchema schema = generator.Generate(typeof(Form));
schema.ToString();
Output:
{
"type": "object",
"properties": {
"someStrings": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
You can try this:
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
Try this ::
public class Employee
{
public string Name { get; set; }
public int Age { get; set; }
public decimal? Salary { get; set; }
}
Employee employee= new Employee
{
Name = "Heisenberg",
Age = 44
};
string jsonWithNullValues = JsonConvert.SerializeObject(person, Formatting.Indented);
output: with null
// {
// "Name": "Heisenberg",
// "Age": 44,
// "Salary": null
// }
string jsonWithOutNullValues = JsonConvert.SerializeObject(employee, Formatting.Indented, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
});
output: without null
// {
// "Name": "Heisenberg",
// "Age": 44
// }
This is the class Database:
namespace vVvBot.Model
{
public class Database
{
public List<CustomCommand> CustomCommands { get; set; }
public List<CustomEvent> CustomEvents { get; set; }
}
}
This is the class for CustomEvent:
namespace vVvBot.Model
{
public class CustomEvent
{
public string Name { get; set; }
public bool Enabled { get; set; }
public List<CustomCommand> Commands { get; set; }
}
}
This is the class CustomCommand:
namespace vVvBot.Model
{
public class CustomCommand
{
public string Keyword { get; set; }
public CommandType Type { get; set; }
public string Message { get; set; }
public bool Enabled { get; set; }
}
}
This is the class where I deserialize and serialize the Database object
namespace vVvBot.Data
{
public class FileJsonContext
{
public Database ReadToObject(string fileName)
{
dynamic jsonData = File.ReadAllText(fileName);
return JsonConvert.DeserializeObject<Database>(jsonData) ?? new Database();
}
public void ObjectToFile(string fileName, Database database)
{
dynamic jsonData = JsonConvert.SerializeObject(database, Formatting.Indented);
File.WriteAllText(fileName, jsonData);
}
}
}
In the file with the issue, this is where I instantiate Database:
private Database _database;
public Database Database => _database ?? (_database = JsonContext.ReadToObject("Commands.txt"));
The line with the issue is:
var messageindex = Database.CustomEvents[index].Commands.FindLastIndex(x => x.Type == CommandType.Welcome);
It tries to complete the line but immediately returns because its comes back with null. There is a List in the custom events that should call the customcommand list so I can access the object. Not sure why it comes back to NULL.
The Json File includes:
{
"CustomCommands": [
{
"Keyword": "Hello",
"Type": 0,
"Message": "World",
"Enabled": true
},
{
"Keyword": "Test",
"Type": 0,
"Message": "test",
"Enabled": true
},
{
"Keyword": "greeting",
"Type": 3,
"Message": "this isnt a test ",
"Enabled": true
},
{
"Keyword": "leaving",
"Type": 4,
"Message": "Sorry to see you go ",
"Enabled": true
},
{
"Keyword": "faq",
"Type": 1,
"Message": "This is a FAQ TEST ",
"Enabled": true
},
{
"Keyword": "Hi",
"Type": 0,
"Message": "Hilo ",
"Enabled": false
},
{
"Keyword": "Hi",
"Type": 0,
"Message": "Hilo ",
"Enabled": false
}
],
"CustomEvents": [
{
"Name": "greeting",
"Enabled": true
},
{
"Name": "leaving",
"Enabled": true
}
]
}
i had this problem a long time ago and i thought the problem was from Unicode.
so i wrote a function for this . you can use it :
List<T> ToJson<T>(byte[] byteArray) where T : new()
{
MemoryStream stream = new MemoryStream(byteArray);
JsonSerializer se = new JsonSerializer();
StreamReader re = new StreamReader(stream);
JsonTextReader reader = new JsonTextReader(re);
return se.Deserialize<List<T>>(reader);
}
and i use this function Like this:
ToJson(data.ToArray());
data is a MemoryStream.
I have this JSON:
[
{
"Attributes": [
{
"Key": "Name",
"Value": {
"Value": "Acc 1",
"Values": [
"Acc 1"
]
}
},
{
"Key": "Id",
"Value": {
"Value": "1",
"Values": [
"1"
]
}
}
],
"Name": "account",
"Id": "1"
},
{
"Attributes": [
{
"Key": "Name",
"Value": {
"Value": "Acc 2",
"Values": [
"Acc 2"
]
}
},
{
"Key": "Id",
"Value": {
"Value": "2",
"Values": [
"2"
]
}
}
],
"Name": "account",
"Id": "2"
},
{
"Attributes": [
{
"Key": "Name",
"Value": {
"Value": "Acc 3",
"Values": [
"Acc 3"
]
}
},
{
"Key": "Id",
"Value": {
"Value": "3",
"Values": [
"3"
]
}
}
],
"Name": "account",
"Id": "2"
}
]
And I have these classes:
public class RetrieveMultipleResponse
{
public List<Attribute> Attributes { get; set; }
public string Name { get; set; }
public string Id { get; set; }
}
public class Value
{
[JsonProperty("Value")]
public string value { get; set; }
public List<string> Values { get; set; }
}
public class Attribute
{
public string Key { get; set; }
public Value Value { get; set; }
}
I am trying to deserialize the above JSON using the code below:
var objResponse1 = JsonConvert.DeserializeObject<RetrieveMultipleResponse>(JsonStr);
but I am getting this error:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type
'test.Model.RetrieveMultipleResponse' because the type requires a JSON
object (e.g. {"name":"value"}) to deserialize correctly. To fix this
error either change the JSON to a JSON object (e.g. {"name":"value"})
or change the deserialized type to an array or a type that implements
a collection interface (e.g. ICollection, IList) like List that can
be deserialized from a JSON array. JsonArrayAttribute can also be
added to the type to force it to deserialize from a JSON array. Path
'', line 1, position 1.
Your json string is wrapped within square brackets ([]), hence it is interpreted as array instead of single RetrieveMultipleResponse object. Therefore, you need to deserialize it to type collection of RetrieveMultipleResponse, for example :
var objResponse1 =
JsonConvert.DeserializeObject<List<RetrieveMultipleResponse>>(JsonStr);
If one wants to support Generics (in an extension method) this is the pattern...
public static List<T> Deserialize<T>(this string SerializedJSONString)
{
var stuff = JsonConvert.DeserializeObject<List<T>>(SerializedJSONString);
return stuff;
}
It is used like this:
var rc = new MyHttpClient(URL);
//This response is the JSON Array (see posts above)
var response = rc.SendRequest();
var data = response.Deserialize<MyClassType>();
MyClassType looks like this (must match name value pairs of JSON array)
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class MyClassType
{
[JsonProperty(PropertyName = "Id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "Description")]
public string Description { get; set; }
[JsonProperty(PropertyName = "Manager")]
public string Manager { get; set; }
[JsonProperty(PropertyName = "LastUpdate")]
public DateTime LastUpdate { get; set; }
}
Use NUGET to download Newtonsoft.Json add a reference where needed...
using Newtonsoft.Json;
Can't add a comment to the solution but that didn't work for me. The solution that worked for me was to use:
var des = (MyClass)Newtonsoft.Json.JsonConvert.DeserializeObject(response, typeof(MyClass));
return des.data.Count.ToString();
Deserializing JSON array into strongly typed .NET object
Use this, FrontData is JSON string:
var objResponse1 = JsonConvert.DeserializeObject<List<DataTransfer>>(FrontData);
and extract list:
var a = objResponse1[0];
var b = a.CustomerData;
To extract the first element (Key) try this method and it will be the same for the others :
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.GetAsync("Your URL"))
{
var apiResponse = await response.Content.ReadAsStringAsync();
var list = JObject.Parse(apiResponse)["Attributes"].Select(el => new { Key= (string)el["Key"] }).ToList();
var Keys= list.Select(p => p.Key).ToList();
}
}
var objResponse1 =
JsonConvert.DeserializeObject<List<RetrieveMultipleResponse>>(JsonStr);
worked!