Related
I'm new in C# and I want to get a JSON from my app in heroku. Before I did it in javascript with no problems but I'm triying to do it in C# now.
My code is:
namespace FirstApp
{
public class AOA
{
public Data data { get; set; }
public static void Main()
{
var json = string.Empty;
var aoa = new List<AOA>();
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(#"http://beautyglam.herokuapp.com/aoa/eyeliner?page=1");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
json = reader.ReadToEnd();
aoa = JsonConvert.DeserializeObject<List<AOA>>(json);
Console.WriteLine("DATOS");
Console.WriteLine(json);
Console.WriteLine(aoa[0].data);
}
catch(Exception e)
{
Console.WriteLine("Errorrr: " + e);
}
}
}
public class Data
{
public string category { get; set; }
public int pages { get; set; }
public string name { get; set; }
public int? price { get; set; }
public string id { get; set; }
public string img { get; set; }
}
}
The returned json is something like:
[{"category":"AOA Eye Liner","pages":0},{"name":"AOA Starlet Eyeliner- Spotlight","price":150,"id":"751612657678","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-164-MAIN_large.jpg?v=1539192189"},{"name":"AOA Starlet Eyeliner- Hollywood","price":150,"id":"751612592142","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-166-MAIN_large.jpg?v=1539192156"},{"name":"AOA Starlet Eyeliner- Fame","price":150,"id":"751612559374","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-169-MAIN_large.jpg?v=1539192087"},{"name":"AOA Starlet Eyeliner- Superstar","price":150,"id":"751612526606","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-167-MAIN_large.jpg?v=1539192203"},{"name":"AOA Starlet Eyeliner- Paparazzi","price":150,"id":"751612461070","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-165-MAIN_large.jpg?v=1539192338"},{"name":"AOA Starlet Eyeliner- Golden Girl","price":150,"id":"751612329998","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-168-MAIN_large.jpg?v=1539192127"},{"name":"AOA Wonder Liquid Liner - Black","price":150,"id":"194917793806","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-036-1_large.jpg?v=1522944978"},{"name":"AOA Wonder Liquid Liner - Dark Brown","price":150,"id":"194917335054","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-037-1_large.jpg?v=1522944879"}]
I want to use it like in Javascript, for example:
aoa[0].name;
Your class representation of your json structure is not valid for your example. Also, your json structure needs to be parsed with some special deserializer because it is not contains consist values.
You have an array of json object but they are not have same type.
You need 3 classes which one represents category and pages, one represents name,price,id,img and one for the root which containts those two classes.
Here is what it should look like:
class RootObj {
public Category category { get; set; }
public List<Detail> details { get; set; }
}
class Category {
public string category { get; set; }
public int pages { get; set; }
}
class Detail {
public string name { get; set; }
public int price { get; set; }
public string id { get; set; }
public string img { get; set; }
}
Here is custom deserializer:
class CustomObjectConverter<T> : JsonConverter
{
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)
{
JArray array = JArray.Load(reader);
RootObj result = new RootObj();
result.category = array[0].ToObject<Category>();
array.RemoveAt(0);
result.details = array.ToObject<List<Detail>>();
return result;
}
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(RootObj));
}
}
Main :
string jsonText = File.ReadAllText("json.txt");
var deserializer = new JsonSerializerSettings();
deserializer.Converters.Add(new CustomObjectConverter<RootObj>());
var result = JsonConvert.DeserializeObject<RootObj>(jsonText, deserializer);
Now you can access the properties as :
Console.WriteLine(result.category.category);
Output is :
AOA Eye Liner
You can customize it according to your use cases.
I am in search a method that deserializes an array (without member names) to a C# object. Working and expected examples are provided and I have seen many similar posts but not quite what I am looking for hence why felt to ask out for some assistance.
Do I need to take the approach of implementing custom deserialization or am I missing out something already existing?
// Deserialize Works This Way
public class Order
{
public string orderNo { get; set; }
public string customerNo { get; set; }
public List<List<double>> items { get; set; }
}
// Expected Covert Type.
public class OrderExpected
{
public string orderNo { get; set; }
public string customerNo { get; set; }
public List<OrderItem> items { get; set; }
}
public class OrderItem
{
public int itemId { get; set; }
public decimal price { get; set; }
public decimal quantity { get; set; }
}
Code I have tried and what I would like to get working:
var json = "{\"orderNo\":\"AO1234\",\"customerNo\":\"C0129999\",\"items\":[[255, 1.65, 20951.60],[266, 1.80, 20000.00],[277, 1.90,0.50]]}";
// Works OK, but ins't what I am after
var order = JsonConvert.DeserializeObject<Order>(json);
// I'd like to get some help to get this approch working.
var orderexpected = JsonConvert.DeserializeObject<OrderExpected>(json);
Further information on items array:
The items array is going to consist of arrays which have fixed length of 3 and values represent itemId, price and quantity respectively.
P.S. I am consuming an API which is out of my control.
this can help you..
public class OrderExpected
{
public string orderNo { get; set; }
public string customerNo { get; set; }
public List<OrderItem> items { get; set; }
}
[JsonConverter(typeof(OrderItemConverter))]
public class OrderItem
{
public int itemId { get; set; }
public decimal price { get; set; }
public decimal quantity { get; set; }
}
public class OrderItemConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.Name.Equals("OrderItem");
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JArray array = JArray.Load(reader);
return new OrderItem {
itemId = array[0].ToObject<int>(),
price = array[1].ToObject<decimal>(),
quantity = array[2].ToObject<decimal>()
};
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var orderItem = value as OrderItem;
JArray arra = new JArray();
arra.Add(orderItem.itemId);
arra.Add(orderItem.price);
arra.Add(orderItem.quantity);
arra.WriteTo(writer);
}
}
using..
string jsonString = "{\"orderNo\":\"AO1234\",\"customerNo\":\"C0129999\",\"items\":[[255, 1.65, 20951.60],[266, 1.80, 20000.00],[277, 1.90,0.50]]}";
var objectResult = JsonConvert.DeserializeObject<OrderExpected>(jsonString);
var serializationResult = JsonConvert.SerializeObject(objectResult);
Console.WriteLine(serializationResult);
// output : {"orderNo":"AO1234","customerNo":"C0129999","items":[[255,1.65,20951.6],[266,1.8,20000.0],[277,1.9,0.5]]}
You can use custom JsonConverter for specified property by using attribute: JsonConverter(typeof(YourCustomConverter))
In your case simple examle should looks like this:
public class OrderExpected
{
public string OrderNo { get; set; }
public string CustomerNo { get; set; }
[JsonConverter(typeof(OrderItemConverter))]
public List<OrderItem> Items { get; set; }
}
public class OrderItemConverter : JsonConverter
{
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)
{
if (reader.TokenType == JsonToken.Null)
return null;
var jArray = JArray.Load(reader);
var result = new List<OrderItem>();
foreach (var arrayItem in jArray)
{
var innerJArray = arrayItem as JArray;
if(innerJArray?.Count != 3)
continue;
result.Add(new OrderItem
{
ItemId = (int) innerJArray[0],
Price = (decimal)innerJArray[1],
Quantity = (decimal)innerJArray[2]
});
}
return result;
}
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
}
And deserialize your json as usual.
var obj = JsonConvert.DeserializeObject<OrderExpected>(json);
Alright, I agree with Levent. I just want to develop this answer!
in Json.Net side use this attribute [JsonExtensionData] when Json string contains properties without property names
[Serializable]
[JsonObject]
public class Price
{
[JsonExtensionData]
public IDictionary<string, JToken> Values { get; set; }
[JsonProperty("vendor")]
public Dictionary<string, string> vendor { get; set; }
}
I have a flat object that I would like to group into sections in order to make parsing it easier. This is the basic idea of what my class currently looks like:
class Populations {
public string US { get; set; }
public string Canada { get; set; }
public string Germany { get; set; }
public string England { get; set; }
}
But this is what I want it to be serialized into when populated with data:
{
"Populations": {
"North America": {
"US": "318 million",
"Canada": "35 million"
},
"Europe": {
"Germany": "80 million",
"England": "53 million"
}
}
}
What I am trying to do is wrap my countries into continents without actually creating new continent classes. Is this possible with a tool like Json.Net or do I simply have to create a NorthAmerica class with two properties and then create a Europe class with two properties? Is it possible an annotation exists to allow me group together some of these properties?
There is no built-in mechanism in Json.Net to do this grouping as you describe; however, you could make a custom JsonConverter to do it if that's what you really want. Something like this might work:
class GroupAttribute : Attribute
{
public string Name { get; set; }
public GroupAttribute(string name)
{
Name = name;
}
}
class GroupingConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JObject obj = new JObject();
Type type = value.GetType();
foreach (PropertyInfo pi in type.GetProperties())
{
JToken propVal = JToken.FromObject(pi.GetValue(value));
GroupAttribute group = pi.GetCustomAttribute<GroupAttribute>();
if (group != null)
{
JObject groupObj = (JObject)obj[group.Name];
if (groupObj == null)
{
groupObj = new JObject();
obj.Add(group.Name, groupObj);
}
groupObj.Add(pi.Name, propVal);
}
else
{
obj.Add(pi.Name, propVal);
}
}
JObject wrapper = new JObject(new JProperty(type.Name, obj));
wrapper.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanRead
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
// CanConvert is not called when a [JsonConverter] attribute is applied
return false;
}
}
You would then mark up your Populations class like this:
[JsonConverter(typeof(GroupingConverter))]
class Populations
{
[Group("North America")]
public string US { get; set; }
[Group("North America")]
public string Canada { get; set; }
[Group("Europe")]
public string Germany { get; set; }
[Group("Europe")]
public string England { get; set; }
}
Finally, serialize like this:
string json = JsonConvert.SerializeObject(populations, Formatting.Indented);
Fiddle: https://dotnetfiddle.net/EPiJue
You could create classes NorthAmerica and Europe, or you could do something like:
class Continent{
string Type { get; set; }
ICollection<Country> Countries { get; set; }
}
This would of course necessitate that all your countries have a common base class or interface.
Seeing as how your JSON doesn't have arrays, you're current classes make this json impossible to create unless you create another class with the exact structure you would want or Select it into a dynamic object.
If you must strictly abide by this JSON, I would encourage you to make a different population class that has a structure like
class Populations {
public NorthAmerica NorthAmerica { get; set; }
public Europe Europe { get; set; }
}
class NorthAmerica{
public string US { get; set; }
public string Canada { get; set; }
}
class Europe{
public string Germany{ get; set; }
public string England{ get; set; }
}
I'm trying to parse a json string with for example [1,2,3] to an array during deserializing.
This is my json data:
[
{
"id": "1",
"district": "1",
"lon": "4.420650000000000000",
"lat": "51.21782000000000000",
"bikes": "19",
"slots": "14",
"zip": "2018",
"address": "Koningin Astridplein",
"addressNumber": null,
"nearbyStations": "3,4,5,24",
"status": "OPN",
"name": "001- Centraal Station - Astrid"
}
]
And this is my c# currently mapping to a regular string, which i would like to be an array of integers.
var AvailabilityMap = new[] { new Station() };
var data = JsonConvert.DeserializeAnonymousType(json, AvailabilityMap);
public class Station
{
public int Id { get; set; }
public double Lon { get; set; }
public double Lat { get; set; }
public int Bikes { get; set; }
public int Slots { get; set; }
public string Address { get; set; }
public string NearbyStations { get; set; }
public string Status { get; set; }
public string Name { get; set; }
}
I have found no way so far to do this in a proper way, without looping trough my current array once more..
Create a custom converter. Something like this:
public class StringToIntEnumerable : JsonConverter
{
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
public override bool CanWrite
{
get
{
return false; // we'll stick to read-only. If you want to be able
// to write it isn't that much harder to do.
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Note: I've skipped over a lot of error checking and trapping here
// but you might want to add some
var str = reader.Value.ToString();
return str.Split(',').Select(s => int.Parse(s));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Now change you class to use the converter by using the JsonConverterAttribute:
public class Station
{
public int Id { get; set; }
public double Lon { get; set; }
public double Lat { get; set; }
public int Bikes { get; set; }
public int Slots { get; set; }
public string Address { get; set; }
[JsonConverter(typeof(StringToIntEnumerable))]
public IEnumerable<int> NearbyStations { get; set; } // or List<int> or int[] if
// you prefer, just make
// sure the convert returns
// the same type
public string Status { get; set; }
public string Name { get; set; }
}
And now to deserialize:
var stations = JsonConvert.DeserializeObject<List<Station>>(json);
Here is a working fiddle that uses a custom JsonConverter.
What we're doing is converting your CSV values into a proper JSON array before we convert the entire JSON string into a Station object.
Custom JsonConverter
ReadJson reads through the JSON string. First, it loads the JSON into a JObject. Next, it gets the nearbyStations property and changes it from a simple CSV string into a JavaScript array. It does this by wrapping the CSV within square brackets. Finally, we use the JsonSerializer to populate our target object and return it.
CanWrite is set to false, because this JsonConverter is only allowed to read JSON not write to JSON. As a result, we don't need to implement WriteJson. The CanConvert tests to make sure that the target object is a Station.
public class StationConverter : JsonConverter
{
public override object ReadJson(
JsonReader r, Type t, object v, JsonSerializer s)
{
JObject jObject = JObject.Load(r);
var prop = jObject.Property("nearbyStations");
var wrapped = string.Format("[{0}]", prop.Value);
JArray jsonArray = JArray.Parse(wrapped);
prop.Value = jsonArray;
var target = new Station();
s.Populate(jObject.CreateReader(), target);
return target;
}
public override void WriteJson(JsonWriter w, object v, JsonSerializer s)
{
throw new NotImplementedException("Unnecessary: CanWrite is false.");
}
public override bool CanWrite
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof (Station);
}
}
Change the Station Class to have an int[]
For the above JsonConverter to to work, change your NearbyStations property to be an int[].
public int[] NearbyStations
{
get;
set;
}
Usage Example with Live Fiddle
Here is an example of how to use it:
var AvailabilityMap =
JsonConvert.DeserializeObject<Station[]>(json, new StationConverter());
Console.WriteLine(AvailabilityMap[0].NearbyStations[0]);
The right answer is to have properly formatted input. In this case:
"nearbyStations": ["3","4","5","24"]
But I was faced with a similar situation in which the data could not be updated, so a solution had to be found. The easiest is to make a getter/setter that won't be touched by the serializer/deserializer. Unfortunately you can't ignore public properties with this serializer out of the box. So you have to do some clever work-arounds like reading into a DTO and using a business object for actual operations.
public class StationDTO
{
public int Id { get; set; }
public double Lon { get; set; }
public double Lat { get; set; }
public int Bikes { get; set; }
public int Slots { get; set; }
public string Address { get; set; }
public string NearbyStations { get; set; }
public string Status { get; set; }
public string Name { get; set; }
}
...
public class Station : StationDTO
{
public List<string> NearbyStationsList
{
get
{
return NearbyStations.Split(',');
}
set
{
NearbyStations = string.Join(",", value);
}
}
}
More information: Newtonsoft ignore attributes?
I have the following json string:
{"Visits":[true,"DockedOnly","leftZone","0","500",0,0,0],
"Weather":[true,"DockedOnly","leftZone","0","0",0,0,1],
"ContactUs":[true,"DockedOnly","leftZone","0","317",0,0,2],
"Birthdays":[true,"DockedOnly","middleZone","0","0",0,0,0],
"Reminders":[true,"DockedOnly","middleZone","0","145",0,0,1],
"Messages":[true,"DockedOnly","middleZone","0","0",0,0,2],
"Availability":[true,"DockedOnly","middleZone","0","0",0,0,3],
"Settings":[false,"DockedOnly","leftzone","0","155",0,0,0]}
Is there anyway to deserialize to something like the following?
[Serializable]
public class WidgetProps
{
public bool Visible { get; set; }
public string DockState { get; set; }
public string Zone { get; set; }
public string Top { get; set; }
public string Left { get; set; }
public int UnusedA { get; set; }
public int UnusedB { get; set; }
public int Position { get; set; }
}
[Serializable]
public class WidgetLayout
{
public WidgetProps Visits { get; set; }
public WidgetProps Weather { get; set; }
public WidgetProps ContactUs { get; set; }
public WidgetProps Birthdays { get; set; }
public WidgetProps Reminders { get; set; }
public WidgetProps Messages { get; set; }
public WidgetProps Availability { get; set; }
public WidgetProps Settings { get; set; }
}
or
public class Widget
{
public string WidgetName { get; set; }
public WidgetProps props { get; set; }
}
List<Widget> MyWidgets;
I am given the json string so I can't change how it is given to me but maybe I could tinker with it after I get it so it will work.
I tried:
string s = "{\"Visits\":[true,\"DockedOnly\",\"leftZone\",\"0\",\"500\",0,0,0],\"Weather\":[true,\"DockedOnly\",\"leftZone\",\"0\",\"0\",0,0,1],\"ContactUs\":[true,\"DockedOnly\",\"leftZone\",\"0\",\"317\",0,0,2],\"Birthdays\":[true,\"DockedOnly\",\"middleZone\",\"0\",\"0\",0,0,0],\"Reminders\":[true,\"DockedOnly\",\"middleZone\",\"0\",\"145\",0,0,1],\"Messages\":[true,\"DockedOnly\",\"middleZone\",\"0\",\"0\",0,0,2],\"Availability\":[true,\"DockedOnly\",\"middleZone\",\"0\",\"0\",0,0,3],\"Settings\":[false,\"DockedOnly\",\"leftzone\",\"0\",\"155\",0,0,0]}}";
var sd = new JavaScriptSerializer().Deserialize < List<Widget>>(s);
and
var sd = new JavaScriptSerializer().Deserialize < WidgetLayout >(s);
This isn't working because you're trying to deserialize an array into an object. The json.NET deserializer will not be able make that conversion.
Because your json arrays have multiple types in them you'll have to deserialize into the smallest common denominator, in this case, object. From there I would recommend writing a method to assign each index to it's corresponding property in WidgetProps.
So basically, define this constructor;
public WidgetProps(object[] props)
{
Visible = (bool)props[0];
DockState = (string)props[1];
// ext
}
I would have something like a WidgetDirty class that I do the initial deserilization into. From there you can create a new instance of WidgetLayout by instantiating each of it's properties like myWidgetLayoutInstance.Visits = new WidgetProp(myWidgetDirtyInstance.Visits); I'd probably hide this mess in a WidgetLayout constructor that takes a WidgetDirty as it's only arg.
yes it's disgusting... but I don't know of any real alternatives because that json's design just isn't very compatible with the C# language. If you're strongly apposed to this I might look at the dynamic type. I haven't used it in C# and probably never will, but I know that deserializing that in a dynamic language like PHP would be no trouble at all.
This doesn't work, because array is normally not deserialized as an object. If possible, I think you should fix the JSON. If you can't do that, and you're using JSON.NET, you can create JsonConverter for WidgetProps that manually converts the array to the object:
class WidgetPropsConverter : JsonConverter
{
public override void WriteJson(
JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotSupportedException();
}
public override object ReadJson(
JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
var array = serializer.Deserialize<object[]>(reader);
return new WidgetProps
{
Visible = (bool)array[0],
DockState = (string)array[1],
Zone = (string)array[2],
Top = (string)array[3],
Left = (string)array[4],
Position = (int)(long)array[7]
};
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(WidgetProps);
}
}
You would then use it like this:
var result = JsonConvert.DeserializeObject<WidgetLayout>(
jsonString, new WidgetPropsConverter());