在ASP.Net MVC中将JSON转换为C#类

5

我正在尝试编写一个API - 他们网站上的预期输出(针对第三方)如下所示:

{
"api_version" : 4 ,
"hotel_ids" : [97497],   
"hotels" :
    [
        {
            "hotel_id": 97497,
            "room_types":
                {
                    "Fenway Room":
                        {
                            "url": "someurlhere",
                            "price": 178.50, 
                            "room_code": "SINGLE"                               
                        }
                }
        }
    ]
}

我正在使用在线工具:http://json2csharp.com/

它给出了以下类:

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; }
}

您可以在RoomTypes中查看:

FenwayRoom __invalid_name__Fenway Room { get; set; }

我想知道他们的JSON规范是否有误,或者我是否可以创建类来返回他们期望的JSON?
在这个例子中,我相信房间类型“芬威客房”是一个变量 - 所以我认为它不能同时是一个类名。但也许我不知道如何创建这样的类。
我只是无法弄清楚“芬威客房” - 我认为它需要像这样的内容:“房间名称”:“芬威客房” - 但也许还有其他定义类的方法,使其不需要标签“房间名称”。
如果您能帮忙确认是否可以创建类来匹配他们的JSON,我将不胜感激。
谢谢,Mark

2
问题似乎在于“Fenway Room”中有一个空格 - 因此,该工具无法自动生成其映射,因为标识符中不允许使用空格。因此,您可能需要使用一些自定义序列化技术,而不是依赖于直接标识符映射。当然,如果供应商可以修改其提供的内容以删除空格,那就更好了。 - Stephen Byrne
嗨,Alex - 不是的,那是什么?我必须创建一个对象来在我的MVC C#代码中返回 - 并且该对象必须返回上面粘贴的示例代码。我只是想不出"Fenway Room"怎么办 - 我认为它需要类似于:"房间名称":"Fenway Room"这样的东西 - 但也许有另一种定义类的方式,使其不需要标签"房间名称"。谢谢,马克 - Mark
我的建议是要么手动完成,要么使用类似于JSON.net这样的工具来读取对象而不需要强类型。自动化工具不会查看像room_types这样的属性并认为*它应该是一个数组,因为它在末尾有一个's'*。它将生成一个字面对象。编写一个合理的结构不应该花费太长时间。 - CodingIntrigue
嗨,史蒂芬 - 这是关于TripAdvisor的 - 我必须遵守他们的规定,他们不会为我改变 :( - Mark
阅读有关“JavaScriptSerializer”以及序列化的一般知识。这是一个大话题。 http://msdn.microsoft.com/en-us/library/vstudio/ms233843.aspx 但我认为您不能通过json“创建”类。(动态?) - Alex Denysenko
显示剩余3条评论
4个回答

1
将你的类更改为以下结构:
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; }
}

创建以下类,实现JsonConverter抽象类:
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)
    {
        //
    }
}

按照以下方式实现 MyJsonConverter<T> 类:

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();
    }
}

现在您可以像这样进行反序列化/序列化:

var result = JsonConvert
    .DeserializeObject<Rootobject>(jsonText, new RoomConverter());
var serialized = JsonConvert
    .SerializeObject(result, new RoomConverter());

1
使用 Json.NET 时的输出。
"room_types":
{
    "Fenway Room":
    {
        "url": "someurlhere",
        "price": 178.50, 
        "room_code": "SINGLE"                               
        }
    }
}

这是你在序列化字典时得到的结果。

将你的类更改为

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; }
}

这一切都建立在使用Json.NET的基础上,它可以免费提供字典的序列化/反序列化功能。你也可以使用.NET框架的序列化器,但需要额外的工作。

0
尝试添加JsonPropteryAttribute。
public class RoomTypes
{
    [JsonProperty(PropertyName="FenWay Room")]
    public FenwayRoom room { get; set; }
}

0
如果您使用此工具(http://jsonclassgenerator.codeplex.com/),它将生成支持这些属性名称的略微更好的C#代码。
// 由Xamasoft JSON类生成器生成 // 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; }
    }

}

抱歉,我觉得我没有表达清楚。 "FenwayRoom" 是一个房间名称,不是一个类 - 所以如果我有50个不同的房间,我不认为我可以在Visual Studio的C#代码中动态创建类。 我相信 "FenwayRoom" 应该是 "RoomName": "FenwayRoom" - 但我想知道是否有一个默认属性,这样 "FenwayRoom" 就不需要 "RoomName",这样我就可以返回API期望的JSON了。谢谢,马克 - Mark
对于RoomType对象,API中的描述为:room_types 使用短描述作为键和可用性房间类型对象作为值的映射。-那么在C#类中如何使用动态名称作为键呢?也许我没有正确地提出问题-我会再次发布-并感谢大家的帮助。 - Mark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接