反序列化在C#中具有int作为键的JSON

Afi*_*iku 5 c# json servicestack json-deserialization

我试图反序列化这个JSON

{
"39": {
    "category": "Miscellaneous",
    "country_whitelist": [],
    "name": "domain.com",
    "url_blacklist": [],
    "country_blacklist": [],
    "url_whitelist": [
        "domain.com"
    ],
    "deals": {
        "425215": {
            "status": "Ok",
            "type": "",
            "code": "CODE",
            "end_date": "2014-03-01 04:00:00",
            "title": "RandomTitle",
            "url": "http://domain.com/foo",
            "text": "Text Text Text",
            "long_title": "Longer Text"
        },
        "425216": {
            "status": "Ok",
            "type": "",
            "code": "CODE2",
            "end_date": "2014-03-01 04:00:00",
            "title": "RandomTitle2",
            "url": "http://domain.com/bar",
            "text": "Text Text Text",
            "long_title": "Longer Text"
        }
    },
    "88x31": "http://someimage/88x31.png",
    "subcategory": "Other"
 },
"40": {
    "category": "Miscellaneous",
    "country_whitelist": [],
    "name": "domain.com",
    "url_blacklist": [],
    "country_blacklist": [],
    "url_whitelist": [
        "domain.com"
    ],
    "products": {
        "425215": {
            "status": "Ok",
            "type": "",
            "code": "CODE",
            "end_date": "2014-03-01 04:00:00",
            "title": "RandomTitle",
            "url": "http://domain.com/foo",
            "text": "Text Text Text",
            "long_title": "Longer Text"
        },
        "425216": {
            "status": "Ok",
            "type": "",
            "code": "CODE2",
            "end_date": "2014-03-01 04:00:00",
            "title": "RandomTitle2",
            "url": "http://domain.com/bar",
            "text": "Text Text Text",
            "long_title": "Longer Text"
        }
    },
    "88x31": "http://someimage/88x31.png",
    "subcategory": "Other"
 }
}
Run Code Online (Sandbox Code Playgroud)

我尝试使用Json.NET,我尝试使用ServiceStack的反序列化器,但我似乎无法获得此JSON的任何类型的表示.

阻止我的主要事情我相信是键是Int但我无法控制我收到的JSON.

这是我建立的C#类

public class product
{
    public string status { get; set; }
    public string type { get; set; }
    public string code { get; set; }
    public string end_date { get; set; }
    public string title { get; set; }
    public string url { get; set; }
    public string text { get; set; }
    public string long_title { get; set; }
}

public class Merchant
{
    public string category { get; set; }
    public List<string> country_whitelist { get; set; }
    public string name { get; set; }
    public List<string> url_blacklist { get; set; }
    public List<string> country_blacklist { get; set; }
    public List<string> url_whitelist { get; set; }
    public List<product> products { get; set; }
    public string subcategory { get; set; }
}

public class Data
{
    public Dictionary<int, Merchant> MainMerchants { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我更喜欢使用ServiceStack,但任何其他有效的解串器都会很棒

var data = client.Get(json);

Sco*_*ott 7

正确映射数据类型:

可以反序列化您的JSON.正确识别后,您可以反序列化为Dictionary<int, Merchant>.

但是你需要productsMerchant课堂上改变你的定义Dictionary<int, Product>.它需要是一个字典来处理您的数字键.List<Product>不行.

另外,为了处理88x31属性,你可以使用DataMember(Name = '88x31')映射将它映射到c#likes之类的东西image88x31.不幸的是,这确实意味着您的DTO属性成为选择加入,因此您需要装饰所有成员.using System.Runtime.Serialization;

完成这些更改后:

// Note I capitalized Product
public class Product
{
    public string status { get; set; }
    public string type { get; set; }
    public string code { get; set; }
    public string end_date { get; set; }
    public string title { get; set; }
    public string url { get; set; }
    public string text { get; set; }
    public string long_title { get; set; }
}

/*
 * Use DataMember to map the keys starting with numbers to an alternative c# compatible name.
 * Unfortunately this requires properties to opt in to the data contract.
 */
[DataContract]
public class Merchant
{
    [DataMember]
    public string category { get; set; }

    [DataMember]
    public List<string> country_whitelist { get; set; }

    [DataMember]
    public string name { get; set; }

    [DataMember]
    public List<string> url_blacklist { get; set; }

    [DataMember]
    public List<string> country_blacklist { get; set; }

    [DataMember]
    public List<string> url_whitelist { get; set; }

    [DataMember]
    public Dictionary<int, Product>  products { get; set; }

    [DataMember]
    public string sub_category { get; set; }

    // This maps the 88x31 key to a c# appropriate name
    [DataMember(Name = "88x31")]
    public string image88x31 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后,您将能够Dictionary<int, Merchant>无任何问题地反序列化.

JsonSerializer.DeserializeFromString<Dictionary<int, Merchant>>("YOUR JSON STRING");
Run Code Online (Sandbox Code Playgroud)

在ServiceStack服务中使用:

如果您希望能够将此请求直接发送到ServiceStack服务,则可以使用a RequestBinder反序列化为此复杂类型.鉴于此服务:

请求DTO:

[Route("/Merchants", "POST")]
public class MerchantsRequest
{
    public Dictionary<int, Merchant> MainMerchants { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

简单的行动方法:

public class MerchantsService : Service
{
    public void Post(MerchantsRequest request)
    {
        var merchant39 = request.MainMerchants.First(p=>p.Key == 39).Value;
        Console.WriteLine("Name: {0}\nImage: {1}\nProduct Count: {2}", merchant39.name, merchant39.image88x31, merchant39.products.Count);

        var merchant40 = request.MainMerchants.First(p=>p.Key == 40).Value;
        Console.WriteLine("Name: {0}\nImage: {1}\nProduct Count: {2}", merchant40.name, merchant40.image88x31, merchant40.products.Count);
    }
}
Run Code Online (Sandbox Code Playgroud)

AppHost配置:

在您的AppHost Configure方法中,您需要将粘合剂添加到请求类型.即typeof(MerchantsRequest)如此:

public override void Configure(Funq.Container container)
{
    Func<IRequest, object> merchantsRequestBinder = delegate(IRequest request) {
        var json = WebUtility.HtmlDecode( request.GetRawBody() );
        return new MerchantsRequest { MainMerchants = JsonSerializer.DeserializeFromString<Dictionary<int, Merchant>>(json) };
    };

    RequestBinders.Add(typeof(MerchantsRequest), merchantsRequestBinder);

    ...
}
Run Code Online (Sandbox Code Playgroud)

此绑定器方法将您发送的json转换为MerchantsRequest.然后,您可以像常规ServiceStack请求一样使用它.

完整源代码在这里

控制台应用程序的完整工作示例,演示了将复杂JSON转换为服务请求的过程.


注意:我在你的JSON中注意到你deals在一个对象上有属性,而products在另一个对象上,我认为这是一个拼写错误,因为你在类中没有相应的属性deals.