I am trying to deserialize an HTTP Request to a C# POCO class.
The JSON is:
{
"applicationId":"4284f0b0-61f9-4a9d-8894-766f7b9605b5",
"deviceId":"testdevice22",
"messageType":"cloudPropertyChange",
"properties":[
{"name":"CustomerID","value":202},
{"name":"DeviceSerialNumber","value":"devicesa999"},
{"name":"Location","value":{
"alt":0,
"lat":41.29111465188208,
"lon":-80.91897192058899
}}
],
}
The POCO is:
public class CustomEventModel
{
public string applicationId { get; set; }
public string deviceId { get; set; }
public List<PropertyAttribute> properties { get; set; }
}
public class PropertyAttribute
{
public string name { get; set; }
public string value { get; set; }
}
In my Function App I have:
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
var propertyChangeData = JsonConvert.DeserializeObject<CustomEventModel>(requestBody);
The Exception Message is: 2022-05-27T23:14:42.141 [Error] Error in CustomEventModel: Unexpected character encountered while parsing value: {. Path 'properties[7].value', line 1,
It is all related to the Location item. How do I solve this?
The value of "Location" is
{
"alt":0,
"lat":41.29111465188208,
"lon":-80.91897192058899
}
this is a complex object while the other "values" are not. They aren't even the same type. One solution is to create a custom deserializer as documented here: https://www.newtonsoft.com/json/help/html/CustomJsonConverterGeneric.htm
Then write the one-way conversion from the various value types with a custom type (e.g. CustomValue)
public class CustomValueConverter : JsonConverter<CustomValue>
{
public override Version ReadJson(JsonReader reader, Type objectType, CustomValue existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var value = reader.Value;
return new CustomValue(value);
}
}
where your PropertyAttribute class now looks like this:
public class PropertyAttribute
{
public PropertyAttribute() {}
public PropertyAttribute(object value)
{
//handle the various types of input in the constructor
}
public string name { get; set; }
public CustomValue value { get; set; }
}
now you can deserialize using your custom value converter like this:
var thing = JsonConvert.DeserializeObject<CustomEventModel>(json, new CustomValueConverter());
just change a type of a value property from string to object and add Location class
public class PropertyAttribute
{
public string name { get; set; }
private object _value;
public object value
{
get
{
if (_value as JObject !=null)
return ((JObject)_value).ToObject<Location>();
return _value?.ToString();
}
set { _value = value; }
}
}
public class Location
{
public int alt { get; set; }
public double lat { get; set; }
public double lon { get; set; }
}
how to use
var propertyChangeData = JsonConvert.DeserializeObject<CustomEventModel>(requestBody);
Location location = (Location) propertyChangeData.properties.Where(p => p.name=="Location").FirstOrDefault().value;
string DeviceSerialNumber = (string) propertyChangeData.properties.Where(p => p.name=="DeviceSerialNumber").FirstOrDefault().value;
I have a very similar issue to this question here, except my application is in C#, and I can't figure out how to convert the solution unfortunately. I am trying to deserialize a JSON result that looks like this:
"error":[],
"result":
{
"MANAEUR":[
[1619042400,"1.11200","1.13488","1.08341","1.10077","1.09896","58878.56534370",137],
[1619046000,"1.09767","1.12276","1.08490","1.11097","1.10456","25343.25910419",77],
],
"last":1619118000
}
I use the following classes:
public class ResponseBase
{
[JsonProperty(PropertyName = "error")]
public List<string> Error;
}
public class OHLCResponse : ResponseBase
{
[JsonProperty("result")]
public OHLCResult Result;
}
public class OHLCResult
{
[JsonProperty("pair_names")]
public Dictionary<string, OHLC[]> GetHistory;
[JsonProperty("last")]
public long Last;
}
.... and then finally the guts of it:
public class OHLC
{
public int Time;
public decimal Open;
public decimal High;
public decimal Low;
public decimal Close;
public decimal Vwap;
public decimal Volume;
public int Count;
}
I have a standard deserializer class which works for all other calls I am using to the same API, but I cannot get this call to work. When I retrieve OHLCResponse object,I don't get an error, and "Result.Last" is always populated, but the expected array of OHLC items in "Result.GetHistory" is always empty/null. I know that the data has been returned successfully since I can see the data in the variable returned from the WebRequest that I am then passing to the deserializer function, so it must be that I have these classes laid out incorrectly I guess.
Can anyone see what I'm doing wrong?
Many thanks in advance, Dave
The object you posted isn't valid JSON. The outside curly braces are missing. So I am going to assume it should look like this:
{
"error": [],
"result": {
"MANAEUR": [
[1619042400, "1.11200", "1.13488", "1.08341", "1.10077", "1.09896", "58878.56534370", 137],
[1619046000, "1.09767", "1.12276", "1.08490", "1.11097", "1.10456", "25343.25910419", 77],
],
"last": 1619118000
}
}
Anonymous Deserialization
The first method you could do, which may be a tad kludgy since you have to deserialize twice, is use anonymous deserialization.
Let's start by defining some models:
public sealed class OHLCModel
{
public long Time { get; set; }
public decimal Open { get; set; }
public decimal High { get; set; }
public decimal Low { get; set; }
public decimal Close { get; set; }
public decimal Vwap { get; set; }
public decimal Volume { get; set; }
public int Count { get; set; }
}
public sealed class ResultModel
{
[JsonIgnore]
public IEnumerable<OHLCModel> Manaeur { get; set; }
[JsonProperty("last")]
public long Last { get; set; }
}
public sealed class RootModel
{
[JsonProperty("error")]
public List<string> Error { get; set; }
[JsonProperty("result")]
public ResultModel Result { get; set; }
}
As you can see we are ignoring the Manaeur object when serialization happens.
To make this method work, we'd do this:
var json = System.IO.File.ReadAllText(#"c:\users\andy\desktop\test.json");
// First, just grab the object that has the mixed arrays.
// This creates a "template" of the format of the target object
var dto = JsonConvert.DeserializeAnonymousType(json, new
{
Result = new
{
Manaeur = new List<List<object>>()
}
});
// Next, deserialize the rest of it
var fullObject = JsonConvert.DeserializeObject<RootModel>(json);
// transfer the DTO using a Select statement
fullObject.Result.Manaeur = dto.Result.Manaeur.Select(x => new OHLCModel
{
Time = Convert.ToInt64(x[0]),
Open = Convert.ToDecimal(x[1]),
High = Convert.ToDecimal(x[2]),
Low = Convert.ToDecimal(x[3]),
Close = Convert.ToDecimal(x[4]),
Vwap = Convert.ToDecimal(x[5]),
Volume = Convert.ToDecimal(x[6]),
Count = Convert.ToInt32(x[7])
});
This isn't the most ideal solution as you are tightly coupling to the model in a few spots. The ideal way to do this would be to make a custom JsonSerializer.
Use a Custom JsonConverter
First thing we do is change your ResultModel to look like this:
public sealed class ResultModel
{
[JsonConverter(typeof(ManaeurJsonConverter)), JsonProperty("MANAEUR")]
public IEnumerable<OHLCModel> Manaeur { get; set; }
[JsonProperty("last")]
public long Last { get; set; }
}
Then implement a JsonConverter:
public sealed class ManaeurJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => false; // this will never get called
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var lst = JArray.Load(reader).ToObject<List<List<object>>>();
return lst.Select(x => new OHLCModel
{
Time = Convert.ToInt64(x[0]),
Open = Convert.ToDecimal(x[1]),
High = Convert.ToDecimal(x[2]),
Low = Convert.ToDecimal(x[3]),
Close = Convert.ToDecimal(x[4]),
Vwap = Convert.ToDecimal(x[5]),
Volume = Convert.ToDecimal(x[6]),
Count = Convert.ToInt32(x[7])
});
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{ // we don't need to write
throw new NotImplementedException();
}
}
You can then simply call it as so:
var json = System.IO.File.ReadAllText(#"c:\users\andy\desktop\test.json");
var fullObject = JsonConvert.DeserializeObject<RootModel>(json);
Your JSON is not valid, I had to modify it to make it valid JSON (https://jsonformatter.org/). I added the root brackets and removed the comma delimter after the second inner array entry.
Valid JSON:
{
"error":[],
"result":
{
"MANAEUR":[
[1619042400,"1.11200","1.13488","1.08341","1.10077","1.09896","58878.56534370",137],
[1619046000,"1.09767","1.12276","1.08490","1.11097","1.10456","25343.25910419",77]
],
"last":1619118000
}
}
After updating the JSON, I used Visual Studio's 'Paste Special' to generate C# objects from the JSON. The following classes were created.
public class RootObject
{
[JsonProperty("error")]
public object[] Error { get; set; }
[JsonProperty("result")]
public Result Result { get; set; }
}
public class Result
{
[JsonProperty("MANAEUR")]
public object[][] Manaeur { get; set; }
[JsonProperty("last")]
public int Last { get; set; }
}
With the above JSON and classes, I used the following to deserialize the JSON.
string json = "{\"error\":[],\"result\":{\"MANAEUR\":[[1619042400,\"1.11200\",\"1.13488\",\"1.08341\",\"1.10077\",\"1.09896\",\"58878.56534370\",137],[1619046000,\"1.09767\",\"1.12276\",\"1.08490\",\"1.11097\",\"1.10456\",\"25343.25910419\",77]],\"last\":1619118000}}";
var obj = JsonConvert.DeserializeObject<RootObject>(json);
EDIT:
To handle the MANAEUR property where the key label can be different.
Create a JsonConverter...
public class ManaeurConverter : JsonConverter
{
private Dictionary<string, string> propertyMappings { get; set; }
public ManaeurConverter()
{
this.propertyMappings = new Dictionary<string, string>
{
{"NOTMANAEUR","MANAEUR"}
};
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object instance = Activator.CreateInstance(objectType);
var props = objectType.GetTypeInfo().DeclaredProperties.ToList();
JObject jo = JObject.Load(reader);
foreach (JProperty jp in jo.Properties())
{
if (!propertyMappings.TryGetValue(jp.Name, out var name))
name = jp.Name;
PropertyInfo prop = props.FirstOrDefault(pi =>
pi.CanWrite && pi.GetCustomAttribute<JsonPropertyAttribute>().PropertyName == name);
prop?.SetValue(instance, jp.Value.ToObject(prop.PropertyType, serializer));
}
return instance;
}
public override bool CanConvert(Type objectType)
{
return objectType.GetTypeInfo().IsClass;
}
public override bool CanWrite => false;
}
... Add the JsonConverter attribute to the class...
[JsonConverter(typeof(ManaeurConverter))]
public class Result
{
[JsonProperty("MANAEUR")]
public object[][] Manaeur { get; set; }
[JsonProperty("last")]
public int Last { get; set; }
}
... and parse like so...
string json_Manaeur = "{\"error\":[],\"result\":{\"MANAEUR\":[[1619042400,\"1.11200\",\"1.13488\",\"1.08341\",\"1.10077\",\"1.09896\",\"58878.56534370\",137],[1619046000,\"1.09767\",\"1.12276\",\"1.08490\",\"1.11097\",\"1.10456\",\"25343.25910419\",77]],\"last\":1619118000}}";
string json_Not_Manaeur = "{\"error\":[],\"result\":{\"NOTMANAEUR\":[[1619042400,\"1.11200\",\"1.13488\",\"1.08341\",\"1.10077\",\"1.09896\",\"58878.56534370\",137],[1619046000,\"1.09767\",\"1.12276\",\"1.08490\",\"1.11097\",\"1.10456\",\"25343.25910419\",77]],\"last\":1619118000}}";
var objManaeur = JsonConvert.DeserializeObject<RootObject>(json_Manaeur);
var objNotManaeur = JsonConvert.DeserializeObject<RootObject>(json_Not_Manaeur);
I need to convert JSON object to entity,
I have many entities and I don't want to write my code some times, so I built an entity-base class and I want to do deserialize to entity (without know which derived-entity call to the base-entity).
Can I do it?
This is my base class (It is abstract class)
public abstract class AbstractEntity
{
EntityState EntityState { get; set; }
DateTime CreatedDate { get; set; }
DateTime? ModifiedDate { get; set; }
string CreatedBy { get; set; }
string ModifiedBy { get; set; }
public EntityState getEntityState()
{
return EntityState;
}
public void SetEntityState(EntityState entityState)
{
EntityState = entityState;
}
}
The first ent:
public class TABLE1: AbstractEntity
{
public TABLE1();
public string ID{ get; set; }
public string ADDRESS{ get; set; }
public virtual ICollection<TABLE2> TABLE2 { get; set; }
}
The second ent:
public class TABLE2: AbstractEntity
{
public TABLE2();
public string ID{ get; set; }
public string ADDRESS{ get; set; }
public virtual TABLE1 TABLE1{ get; set; }
}
The duplicate linked is probably a better general-purpose solution:
public class AbstractEntityConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(AbstractEntity);
}
public override object ReadJson(JsonReader reader,
Type objectType, object existingValue, JsonSerializer serializer)
{
JObject item = JObject.Load(reader);
var type = item["TYPE"].Value<string>();
switch (type)
{
case "TABLE1":
return item.ToObject<TABLE1>();
case "TABLE2":
return item.ToObject<TABLE2>();
default:
return null;
}
}
public override void WriteJson(JsonWriter writer,
object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Usage:
string json = "{\"TYPE\":\"TABLE1\",\"CreatedDate\":\"2018-06-10T08:00:00.000Z\",\"CreatedBy\":\"John\",\"ID\":\"1\",\"ADDRESS\":\"1 Road Street\",\"TABLE2\":[{\"CreatedDate\":\"2018-06-10T08:00:00.000Z\",\"CreatedBy\":\"John\",\"ID\":\"2\",\"ADDRESS\":\"2 Road Street\"}]}";
var settings = new JsonSerializerSettings()
{
Converters = new List<JsonConverter>()
{
new AbstractEntityConverter()
}
};
var obj = JsonConvert.DeserializeObject<AbstractEntity>(json, settings);
Of course, you can define your JsonSettings at a central location so that you don't have to keep writing the declaration every time you use it.
P.S. I've opted to assume a "type" property since you didn't show your JSON, or your method of determining which class to deserialize to. Replace with your own logic as needed.
Try it online
You can use JObject from Newtonsoft.Json library. This is the site https://www.newtonsoft.com/json to refer on how to use it. And, a lot of code samples as well can be found here https://www.newtonsoft.com/json/help/html/Samples.htm.
For example:
using Newtonsoft.Json.Serialization;
public void Foo(string jsonData){
var objData = (JObject)JsonConvert.DeserializeObject(jsonData); // Deserialize json data
dynamic jObject = new JObject();
jObject.ID = objData.Value<string>("ID");
jObject.Address = objData.Value<string>("Address");
jObject.TABLE2 = objData.Value<JArray>("TABLE2");
}
In the above code sample, jObject which has a dynamic type that can be converted to which type you want.
Hope this helps.
I have been working with the project, where i have to make external RESTful service call to get some data.
The problem i'm facing here is, the response i'm getting from the service is different on different scenario. For example.
On one scenario, i'm getting below response
{
"id":3000056,
"posted_date":"2016-04-15T07:16:47+00:00",
"current_status":"initialized",
"customer":{
"name" : "George",
"lastName" : "Mike"
},
"application_address":{
"addressLine1" : "Lin1",
"addressLine2" : "Lin2",
}
}
In the other scenario, im getting below response
{
"id":3000057,
"posted_date":"2016-04-15T07:16:47+00:00",
"current_status":"initialized",
"customer":[],
"application_address":[]
}
The problem here is, i have below model, and i'm deserializing it by newtonsoft deserailization.
public class Response
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("posted_date")]
public DateTime PostedDate { get; set; }
[JsonProperty("current_status")]
public string CurrentStatus { get; set; }
[JsonProperty("customer")]
public Customer Customer { get; set; }
[JsonProperty("application_address")]
public ApplicationAddress ApplicationAddress { get; set; }
}
public Class Customer
{
public string name { get; set; }
public string lastName { get; set; }
}
public classs ApplicationAddress
{
public string addreesLine1{ get; set; }
public string addreesLine1{ get; set; }
}
For the first response, it will desrialize. But for the second response, the response is not getting deserialized as the response contains [] for Customer and ApplicationAddrees object. While deserializing, it is treating as a array, but actually it is not.
Note : Below code i'm using for Deserializing.
Response response = JsonConvert.DeserializeObject(result);
Is there any configuration we can do before serializing? Is newtonsoft facilitate that feature?
Thanks .
If you are sure that there will be no arrays in this properties, than you can consider using JsonConverter like this:
public class FakeArrayToNullConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return false;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Array)
{
return null;
}
return token.ToObject<T>();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
And then put additional attribure to your model:
[JsonProperty("customer")]
[JsonConverter(typeof(FakeArrayToNullConverter<Customer>))]
public Customer Customers { get; set; }
[JsonProperty("application_address")]
[JsonConverter(typeof(FakeArrayToNullConverter<ApplicationAddress>))]
public ApplicationAddress ApplicationAddressList { get; set; }
And when in your JSON string for this properties it will be an array [], you will simply deserialize it with null object.
You can't instruct deserialize to handle "[]" as something different as it represents an array (are you sure you never will get customers and addresses in those arrays??)
So you could deserialize to an anonymous type and then map it to your structure.
This is just a guess but can you check if this works:
public class ApplicationAddress
{
private readonly string[] _array = new string[2];
public string this[int index]
{
get { return _array[index]; }
set { _array[index] = value; }
}
public string addreesLine1
{
get { return this[0]; }
set { this[0] = value; }
}
public string addreesLine2
{
get { return this[1]; }
set { this[1] = value; }
}
}
I am trying to use Riot games REST API to make a webapp in C#. I am fine with making the requests using RESTSharp but am having some problems using JSON.Net to convert the returned Json to an object. My request returns a JSON string for example:
{\"dyrus\":{\"id\":4136713,\"name\":\"Dyrus\",\"profileIconId\":23,\"summonerLevel\":1,\"revisionDate\":1376908220000}}
I want to deserialize this into an object that has attributes: id, name, profileIconID, summonerLevel and revisionDate.
The problem I am having is that the information is being deserialized as a string because the Dictionary is nested. What is the best way to just retrieve the nested Dictionary portion of the string: {\"id\":4136713,\"name\":\"Dyrus\",\"profileIconId\":23,\"summonerLevel\":1,\"revisionDate\":1376908220000} and convert it into an object?
Thanks for your help!
Edit:
Here is what I have tried:
public class LeagueUser
{
public LeagueUser(string json)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
string jsonString = (string)serializer.DeserializeObject(json);
LeagueUser test = (LeagueUser)serializer.DeserializeObject(jsonString);
}
public int id { get; set; }
public string name { get; set; }
public long revisionDate { get; set; }
}
You don't need the constructor, change LeagueUser class to this
public class LeagueUser
{
public int id { get; set; }
public string name { get; set; }
public long revisionDate { get; set; }
}
and use Json.NET to deserialize the json into a Dictionary<string, LeagueUser>
string jsonStr = "{\"dyrus\":{\"id\":4136713,\"name\":\"Dyrus\",\"profileIconId\":23,\"summonerLevel\":1,\"revisionDate\":1376908220000}}";
var deserializedObject = JsonConvert.DeserializeObject<Dictionary<string, LeagueUser>>(jsonStr);
You can get the LeagueUser object this way
LeagueUser leagueUser = deserializedObject["dyrus"];
You can achieve what you want by creating custom converter for your LeagueUser class:
public class LeagueUserConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(LeagueUser) == objectType;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (!CanConvert(objectType)) return null;
var jObject = JObject.Load(reader);
var user = new LeagueUser
{
Id = Convert.ToInt64(jObject["dyrus"]["id"]),
Name = jObject["dyrus"]["name"].ToString(),
ProfileIconId = Convert.ToInt32(jObject["dyrus"]["profileIconId"]),
SummonerLevel = Convert.ToInt32(jObject["dyrus"]["summonerLevel"]),
RevisionDate = Convert.ToInt64(jObject["dyrus"]["revisionDate"])
};
return user;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Next you need to decorate your class with the defined converter:
[JsonConverter(typeof(LeagueUserConverter))]
public class LeagueUser
{
public long Id { get; set; }
public string Name { get; set; }
public int ProfileIconId { get; set; }
public int SummonerLevel { get; set; }
public long RevisionDate { get; set; }
}
And wherever you need call DeserializeObject method:
var user = JsonConvert.DeserializeObject<LeagueUser>(json);
where the json variable is the json string you posted in your question.