Reputation: 7818
I'm trying to write an API - the expected output (for a 3rd party) as shown on their website is the JSON below:
{
"api_version" : 4 ,
"hotel_ids" : [97497],
"hotels" :
[
{
"hotel_id": 97497,
"room_types":
{
"Fenway Room":
{
"url": "someurlhere",
"price": 178.50,
"room_code": "SINGLE"
}
}
}
]
}
I'm using the online tool: http://json2csharp.com/
It gives me the following classes:
public class FenwayRoom
{
public string url { get; set; }
public double price { get; set; }
public string room_code { get; set; }
}
public class RoomTypes
{
public FenwayRoom __invalid_name__Fenway Room { get; set; }
}
public class Hotel
{
public int hotel_id { get; set; }
public RoomTypes room_types { get; set; }
}
public class RootObject
{
public int api_version { get; set; }
public List<int> hotel_ids { get; set; }
public List<Hotel> hotels { get; set; }
}
You can see in RoomTypes:
FenwayRoom __invalid_name__Fenway Room { get; set; }
I'm wondering if their spec for the JSON is wrong, or is there a way for me to create the classes to return the JSON they are expecting?
In the example, I believe the room type "Fenway Room" is a variable - so I don't think it can also be a class name. But it may just be that I don't know how to create a class like this.
I just can't figure out the "Fenway Room" - which I think needs to have something like: "Room Name":"Fenway Room" - but maybe there is another way of defining the classes so that it doesn't need a label "Room Name".
I'd appreciate any help in confirming if it is possible to create classes to match against their JSON.
Thanks, Mark
Upvotes: 5
Views: 3297
Reputation: 4780
When using Json.NET the output
"room_types":
{
"Fenway Room":
{
"url": "someurlhere",
"price": 178.50,
"room_code": "SINGLE"
}
}
}
look exactly what you would get serializing a Dictionary.
Change your class to
public class Room
{
public string url { get; set; }
public double price { get; set; }
public string room_code { get; set; }
}
public class Hotel
{
public int hotel_id { get; set; }
public Dictionary<string, Room> room_types { get; set; }
}
public class RootObject
{
public int api_version { get; set; }
public List<int> hotel_ids { get; set; }
public List<Hotel> hotels { get; set; }
}
This is all predicated on using Json.NET, which gives you this serialization/deserialization of dictionaries in this format for free. You can do this with the .NET framework serializer, but you need to do extra work.
Upvotes: 1
Reputation: 32601
Alter your classes to the following structure:
public class Rootobject
{
public int api_version { get; set; }
public List<int> hotel_ids { get; set; }
public List<Hotel> hotels { get; set; }
}
public class Hotel
{
public int hotel_id { get; set; }
public Room_Types room_types { get; set; }
}
public class Room_Types
{
public List<Room> Rooms { get; set; }
}
public class Room
{
public string Type { get; set; }
public string Url { get; set; }
public float Price { get; set; }
}
Create the following class, which implements the JsonConverter
abstract class:
public abstract class MyJsonConverter<T> : JsonConverter
{
protected abstract T Create(Type objectType, JObject jObject);
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override object ReadJson
(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
JObject jObject = JObject.Load(reader);
T target = Create(objectType, jObject);
serializer.Populate(jObject.CreateReader(), target);
return target;
}
public override void WriteJson
(JsonWriter writer,
object value,
JsonSerializer serializer)
{
//
}
}
Implement the MyJsonConverter<T>
class as follows:
public class RoomConverter : MyJsonConverter<Room_Types>
{
protected override Room_Types Create(Type objectType, JObject jObject)
{
var rooms = jObject.Cast<JToken>().Select(t => new Room
{
Type = ((JProperty)t).Name,
Url = ((JProperty)t).First
.SelectToken("url").ToString(),
Price = float.Parse(((JProperty)t).First
.SelectToken("price").ToString())
}).ToList();
return new Room_Types() { Rooms = rooms };
}
public override void WriteJson
(JsonWriter writer,
object value,
JsonSerializer serializer)
{
writer.WriteStartObject();
((Room_Types)value).Rooms.ForEach(r =>
{
writer.WritePropertyName(r.Type);
writer.WriteStartObject();
writer.WritePropertyName("url");
writer.WriteValue(r.Url);
writer.WritePropertyName("price");
writer.WriteValue(r.Price);
writer.WriteEndObject();
});
writer.WriteEndObject();
}
}
Now you may deserialize / serialize like this:
var result = JsonConvert
.DeserializeObject<Rootobject>(jsonText, new RoomConverter());
var serialized = JsonConvert
.SerializeObject(result, new RoomConverter());
Upvotes: 1
Reputation: 5213
If you use this tool (http://jsonclassgenerator.codeplex.com/) it will generate slightly better C# that supports those property names.
// Generated by Xamasoft JSON Class Generator // http://www.xamasoft.com/json-class-generator
using System; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Example.SampleResponse1JsonTypes;
namespace Example.SampleResponse1JsonTypes
{
internal class FenwayRoom
{
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("price")]
public double Price { get; set; }
[JsonProperty("room_code")]
public string RoomCode { get; set; }
}
internal class RoomTypes
{
[JsonProperty("Fenway Room")]
public FenwayRoom FenwayRoom { get; set; }
}
internal class Hotel
{
[JsonProperty("hotel_id")]
public int HotelId { get; set; }
[JsonProperty("room_types")]
public RoomTypes RoomTypes { get; set; }
}
}
namespace Example
{
internal class SampleResponse1
{
[JsonProperty("api_version")]
public int ApiVersion { get; set; }
[JsonProperty("hotel_ids")]
public int[] HotelIds { get; set; }
[JsonProperty("hotels")]
public Hotel[] Hotels { get; set; }
}
}
Upvotes: 0
Reputation: 4180
Try adding the JsonPropteryAttribute.
public class RoomTypes
{
[JsonProperty(PropertyName="FenWay Room")]
public FenwayRoom room { get; set; }
}
Upvotes: 0