Deserializing JSON that has an int as a key in C#
c#, json, json-deserialization, servicestack
Solution
Getting your data types mapped correctly:
It is possible to deserialize your JSON. As you correctly identified you can deserialize to a `Dictionary<int, Merchant>`.
But you will need to change your definition of `products` in the `Merchant` class to be a `Dictionary<int, Product>`. It needs to be a dictionary here to handle your numeric key. `List<Product>` won't work.
Also to handle the `88x31` property you can use a `DataMember(Name = '88x31')` mapping to map it to something c# likes, like `image88x31`. Unfortunately this does mean your DTO properties become opt-in so you will then need to decorate all members. Add `using System.Runtime.Serialization;`
Once you make those changes such that:
// 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; }
}
Then you will be able to deserialize into `Dictionary<int, Merchant>` without any issues.
JsonSerializer.DeserializeFromString<Dictionary<int, Merchant>>("YOUR JSON STRING");
Using in a ServiceStack Service:
If you want to be able to send this request directly to a ServiceStack service, then you can use a `RequestBinder` to deserialize into this complex type. Given this service:
Request DTO:
[Route("/Merchants", "POST")]
public class MerchantsRequest
{
public Dictionary<int, Merchant> MainMerchants { get; set; }
}
Simple Action Method:
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);
}
}
AppHost Configuration:
In your `AppHost` `Configure` method you would need to add a binder to the request type. i.e. `typeof(MerchantsRequest)` like so:
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);
...
}
This binder method will convert the json you are sending into a `MerchantsRequest`. Then you can use it like a regular ServiceStack request.
Full Source Code Here
A fully working example of console application, demonstrating the conversion of the complex JSON to a service request.
Note: I notice in your JSON that you have property `deals` on one object, and `products` on another, I assumed this was a typo, as you don't have a corresponding property on in the class for `deals`.
Problem
I am trying to deserialize this 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" } } ``` I tried using Json.NET and I tried using ServiceStack's deserializer but I can't seem to get any type of representation for this JSON. The main thing that is blocking me I believe is that the keys are Int but I don't have control on the JSON I receive. This is the C# classes I have built ``` 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; } } ``` I prefer using ServiceStack but any other deserializer that works will be great var data = client.Get(json);