I am trying to replicate the following JSON structure:
{"result_content": {
"data": {
"city_name" : "Beverly Hills",
"2014-06-05T00:00:00": {
"morning_low": "20",
"daytime_high": "40"
},
"2014-06-06T00:00:00": {
"morning_low": "21",
"daytime_high": "41"
},
"2014-06-07T00:00:00": {
"morning_low": "22",
"daytime_high": "42"
},
"2014-06-08T00:00:00": {
"morning_low": "23",
"daytime_high": "43"
},
"2014-06-09T00:00:00": {
"morning_low": "24",
"daytime_high": "44"
}
}
}
}
But I can't figure out how create the keys to be dynamic using C#.
Here are my object class's
public class Day
{
public string morning_low { get; set; }
public string daytime_high { get; set; }
}
public class Data
{
public string city_name { get; set; }
public List<Day> days { get; set; }
}
public class ResultContent
{
public Data data { get; set; }
}
And here is how im building it all:
ResultContent content = new ResultContent();
content.data = new Data();
content.data.city_name = results.Body.GetCityForecastByZIPResponse.GetCityForecastByZIPResult.City;
foreach (Forecast day in results.Body.GetCityForecastByZIPResponse.GetCityForecastByZIPResult.ForecastResult.Forecast){
Day x = new Day();
x.daytime_high = day.Temperatures.DaytimeHigh;
x.morning_low = day.Temperatures.MorningLow;
content.data.days.Add(x);
}
return JsonConvert.SerializeObject(content);
This just returns a JSON array of days which is not what I want. I have the DateTime in my results object.
This is probably what you're looking for in that case...
void Main()
{
Result result = new Result
{
Data = new Data
{
WeatherData = new List<City>
{
new City
{
Name = "London",
Temp = new Dictionary<DateTime, TemperatureRange>
{
{
DateTime.UtcNow,
new TemperatureRange
{
DayHigh = 0,
MorningLow = 50
}
}
}
}
}
}
};
JsonConvert.SerializeObject(result);
}
public class Result
{
[JsonProperty("result_content")]
public Data Data { get; set; }
}
public class Data
{
[JsonProperty("data")]
public List<City> WeatherData { get; set; }
}
public class City
{
[JsonProperty("city_name")]
public string Name { get; set; }
public Dictionary<DateTime, TemperatureRange> Temp { get; set; }
}
public class TemperatureRange
{
public int MorningLow { get; set; }
public int DayHigh { get; set; }
}
If you really want such a sophisticated format, I'd go with a custom JsonConverter:
public class Day
{
public string morning_low { get; set; }
public string daytime_high { get; set; }
}
[JsonConverter(typeof(Data.Converter))]
public class Data
{
public string city_name { get; set; }
public Dictionary<DateTime, Day> days { get; set; }
public class Converter : JsonConverter
{
public override bool CanConvert(Type type) { return type == typeof(Data); }
public override object ReadJson(JsonReader reader, Type type, object value, JsonSerializer serializer)
{
Data obj = new Data();
obj.days = new Dictionary<DateTime, Day>();
DateTime v;
while (reader.Read() && reader.TokenType != JsonToken.EndObject)
{
if (reader.TokenType != JsonToken.PropertyName)
throw new JsonSerializationException("Unexpected token type");
if ("city_name" == (string)reader.Value)
{
if (obj.city_name != null)
throw new JsonSerializationException("Duplicate key: city_name");
obj.city_name = reader.ReadAsString();
}
else if (DateTime.TryParseExact((string)reader.Value, serializer.DateFormatString,
serializer.Culture, DateTimeStyles.None, out v))
{
reader.Read();
obj.days.Add(v, serializer.Deserialize<Day>(reader));
}
else
{
if (serializer.MissingMemberHandling == MissingMemberHandling.Error)
throw new JsonSerializationException("Unexpected property: " + reader.Value);
reader.Read();
serializer.Deserialize(reader, reader.ValueType);
}
}
return obj;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Data obj = (Data)value;
writer.WriteStartObject();
writer.WritePropertyName("city_name");
writer.WriteValue(obj.city_name);
foreach (var pair in obj.days)
{
writer.WritePropertyName(pair.Key.ToString(serializer.DateFormatString));
serializer.Serialize(writer, pair.Value);
}
writer.WriteEndObject();
}
}
}
public class ResultContent
{
public Data data { get; set; }
}
public class ResultContentRoot
{
public ResultContent result_content { get; set; }
}
public static void Main()
{
var data = new Data();
data.city_name = "New York";
data.days = new Dictionary<DateTime, Day>();
data.days.Add(DateTime.Today, new Day() { morning_low = "24", daytime_high = "29" });
var result_content = new ResultContent();
result_content.data = data;
var root = new ResultContentRoot();
root.result_content = result_content;
var s = JsonConvert.SerializeObject(root);
}
I think it is the only way to mix dictionary and object contracts.
If you only need one-way serialization, you may also go with dynamic. It takes less code:
public class Day
{
public string morning_low { get; set; }
public string daytime_high { get; set; }
}
public class ResultContent
{
public dynamic data { get; set; }
}
public class ResultContentRoot
{
public ResultContent result_content { get; set; }
}
public static void Main()
{
dynamic data = new ExpandoObject();
data.city_name = "New York";
IDictionary<string, object> days = (IDictionary<string, object>)data;
days.Add(DateTime.Today.ToString("yyyy-MM-dd'T'HH:mm:ss"), new Day() { morning_low = "24", daytime_high = "29" });
var result_content = new ResultContent();
result_content.data = data;
var root = new ResultContentRoot();
root.result_content = result_content;
var s = JsonConvert.SerializeObject(root);
}
But it is very close to discard all that strong typing and just construct response with JObjects.
I think it should be an array of days and representing it the way you asked wouldn't be good, because creating a dynamic json format is difficult to parse.
They way you defined it should produce something like this below.
{
"result_content": {
"data": {
"city_name" : "Beverly Hills",
"days" :
[
{
"morning_low": "20",
"daytime_high": "40"
},
{
"morning_low": "21",
"daytime_high": "41"
},
{
"morning_low": "22",
"daytime_high": "42"
},
{
"morning_low": "23",
"daytime_high": "43"
},
{
"morning_low": "24",
"daytime_high": "44"
}
]
}
}
}
What you're missing is the day itself, which should be defined in your Day class. Add it to get:
"days" :
[
{
"day" : "2014-06-05T00:00:00",
"morning_low": "20",
"daytime_high": "40"
}
...
]
Related
Im having problem with deserializing json file into my class.
Json file looks like this:
{
"DataFile": {
"header":{
"version": "123",
"date": "01.01.01",
},
"customer": {
"fID": "12-35-58",
"nameCust": "CompanyName",
"adressCust":{
"zip": "0000",
"city": "Foovile",
"streetNr": "1",
"post": "FoovilePost",
"street": "DunnoStr",
},
},
"content": [
{
"invoice":{
"DFID":"538",
},
"invoice":{
"DFID":"500",
},
"invoice":{
"DFID":"550",
},
"receipt":{
"DFID":"758",
},
"receipt":{
"DFID":"75",
},
}
],
}
}
Everything before content array deserializes fine,so to keep things clear I'll skip parts of my class. Relevant bit looks like this:
class DFFile
{
public DF Df { get; set; }
}
class DF
{
public Header header { get; set; }
public Customer customer { get; set; }
public List<DFContent> content { get; set; }
}
class DFContent
{
public Invoice invoice { get; set; }
public Receipt receipt { get; set; }
}
class Invoice
{
public int DFID { get; set; }
}
class Receipt
{
public int DFID { get; set; }
}
And i deserialize into DFFile instance like this:
DFFile sample = JsonConvert.DeserializeObject<DFFile>(json);
My problem is that it deserializes without errors but sample.DF.content have only one element that have invoice and receipt with last id of each type. And result I'm looking for is list where there is new element for each item of json content array.
I can change my class but way this json is build is set in stone, can't do anything about it and have to deal with it.
Is there any way to stop it changing last element of content and add new one instead?
Your content is set up to hold an array but you only have one item in it which has three invoice and two receipt values. Assuming you want your DFContent to hold either a receipt or invoice, change it to look like this:
"content": [
{"invoice":{
"DFID":"538",
}},
{"invoice":{
"DFID":"500",
}},
{"invoice":{
"DFID":"550",
}},
{"receipt":{
"DFID":"758",
}},
{"receipt":{
"DFID":"75",
}}
],
Since you cannot change the JSON I assumed that you can change your class structure.
Please consider this classes:
class DF
{
// Other properties...
[JsonConverter(typeof(FunnyListConverter))]
public List<Content> content { get; set; }
}
class Content
{
public int DFID { get; set; }
}
class Invoice : Content
{
}
class Receipt : Content
{
}
And here is the FunnyListConverter:
public class FunnyListConverter : 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)
{
var content = new List<Content>();
var currentType = "";
Invoice currentInvoice = null;
Receipt currentReceipt = null;
while (reader.Read())
{
if (reader.TokenType == JsonToken.EndArray)
{
break;
}
if (reader.Value?.ToString() == "invoice")
{
currentInvoice = new Invoice();
currentType = "invoice";
}
if (reader.Value?.ToString() == "receipt")
{
currentReceipt = new Receipt();
currentType = "receipt";
}
if (reader.Path.Contains("DFID") && reader.Value?.ToString() != "DFID")
{
switch (currentType)
{
case "invoice":
currentInvoice.DFID = int.Parse(reader.Value.ToString());
content.Add(currentInvoice);
currentInvoice = null;
break;
case "receipt":
currentReceipt.DFID = int.Parse(reader.Value.ToString());
content.Add(currentReceipt);
currentReceipt = null;
break;
}
}
}
return content;
}
public override bool CanConvert(Type objectType)
{
return true;
}
if (reader.Value?.ToString() == "receipt")
{
currentReceipt = new Receipt();
currentType = "receipt";
}
if (reader.Path.Contains("DFID") && reader.Value?.ToString() != "DFID")
{
switch (currentType)
{
case "invoice":
currentInvoice.DFID = int.Parse(reader.Value.ToString());
content.Add(currentInvoice);
currentInvoice = null;
break;
case "receipt":
currentReceipt.DFID = int.Parse(reader.Value.ToString());
content.Add(currentReceipt);
currentReceipt = null;
break;
}
}
}
return content;
}
public override bool CanConvert(Type objectType)
{
return true;
}
}
I have the following Code:
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver;
using MongoDBTest;
using ServiceStack;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace protocol.server.API.Clients
{
public class ClientService : ServiceStack.Service
{
class CylinderSerializer : SerializerBase<Cylinder>
{
public override void Serialize(MongoDB.Bson.Serialization.BsonSerializationContext context, MongoDB.Bson.Serialization.BsonSerializationArgs args, Cylinder value)
{
var wr = context.Writer;
wr.WriteStartDocument();
wr.WriteName("_id");
wr.WriteObjectId(ObjectId.GenerateNewId());
wr.WriteName("description");
wr.WriteString(value.description.type);
context.Writer.WriteEndDocument();
}
public override Cylinder Deserialize(MongoDB.Bson.Serialization.BsonDeserializationContext context, MongoDB.Bson.Serialization.BsonDeserializationArgs args)
{
context.Reader.ReadStartDocument();
Cylinder a = new Cylinder();
a.Id = context.Reader.ReadObjectId();
while (context.Reader.State != BsonReaderState.Type && context.Reader.ReadBsonType() != BsonType.EndOfDocument)
{
a.description.type = context.Reader.ReadString();
a.description.kind = context.Reader.ReadString();
a.description.year = (short)context.Reader.ReadInt32();
a.description.producer = context.Reader.ReadString();
}
return a;
}
public async Task<List<Cylinder>> Get(GetObjects request)
{
MongoDB.Bson.Serialization.BsonSerializer.RegisterSerializer(typeof(Cylinder), new CylinderSerializer());
IMongoCollection<Cylinder> collection = Connect._database.GetCollection<Cylinder>("Cylinders");
var results = await collection.Find(_ => true).ToListAsync();
return results;
}
}
}
and get the error:
ReadBsonType can only be called when State is Type, not when State is Value
in line:
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
I want to deserialize my objects, they look like this:
{
"_id" : ObjectId("5826010eb831ee1c70df5f16"),
"description" : {
"type" : "Cylinder",
"kind" : "rgdgg",
"year" : NumberInt(1997),
"producer" : "hnnghng",
"brands" : [
"trhr"
],
"model" : [
"Baws"
],
"internalproducerdesignation" : "tw6",
"origin" : "Greece"
},
"elements" : {
"nonspringelements" : NumberInt(0),
"springelements" : NumberInt(11),
"discelements" : NumberInt(0),
"magneticelements" : NumberInt(0),
"activeelements" : NumberInt(11),
"passiveelements" : NumberInt(0),
"totalelements" : NumberInt(11)
},
"profiles" : [
"d1",
"d11"
],
"certifications" : [
"",
""
],
"colors" : [
"brown",
"chrome"
],
"specialfittings" : [
"gf",
"hrthr",
"hgnn",
"ngnn",
"hngngn",
"nghnnn"
],
"cutdepths" : NumberInt(7),
"rareness" : "rare",
"value" : {
"new" : "0",
"used" : "$50"
},
"Blaw" : {
"tgtgt" : 10.0,
"hzhz" : true
},
"availableat" : "gtgtgtgt",
"specialabout" : "jujujuju",
"development" : {
"predecessor" : "",
"follower" : "rfrfr"
},
"media" : [
]
}
My Clinder.cs :
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization.Attributes;
using System;
using System.Collections.Generic;
using System.Globalization;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
namespace protocol.server.API.Clients
{
public class Cylinder
{
[BsonSerializer(typeof(ProductAttributeSerializer))]
public class ProductAttributeSerializer : IBsonSerializer, IBsonArraySerializer
{
public Type ValueType { get { return typeof(List<string>); } }
public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var type = context.Reader.GetCurrentBsonType();
List<String> items = new List<String>();
switch (type)
{
case BsonType.Document:
case BsonType.Array:
context.Reader.ReadStartArray();
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
{
items.Add(context.Reader.ReadString());
}
context.Reader.ReadEndArray();
return new mode(items);
default:
throw new NotImplementedException($"No implementation to deserialize {type}");
}
}
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
{
var d = value;
var attributes = value as List<string>;
if (attributes != null)
{
context.Writer.WriteStartArray();
foreach (string attr in attributes)
{
context.Writer.WriteString(attr);
}
context.Writer.WriteEndArray();
}
}
public bool TryGetItemSerializationInfo(out BsonSerializationInfo serializationInfo)
{
string elementName = null;
var serializer = BsonSerializer.LookupSerializer(typeof(string));
var nominalType = typeof(string);
serializationInfo = new BsonSerializationInfo(elementName, serializer, nominalType);
return true;
}
}
[BsonId]
public ObjectId Id { get; set; }
[BsonSerializer(typeof(ProductAttributeSerializer))]
public class mode
{
public mode(List<String> pItems)
{
this.items = new List<String>();
this.items.Clear();
this.items.AddRange(pItems);
}
public List<String> items { get; set; }
}
public class des
{
public string type { get; set; }
public string kind { get; set; }
public short year { get; set; }
public string producer { get; set; }
public List<string> brands { get; set; }
public string internalproducerdesignation { get; set; }
public string origin { get; set; }
public mode model { get; set; }
}
public class elem
{
public short nonspringelements { get; set; }
public short springelements { get; set; }
public short discelements { get; set; }
public short magneticelements { get; set; }
public short activeelements { get; set; }
public short passiveelements { get; set; }
public short totalelements { get; set; }
}
public des description = new des();
public elem elements = new elem();
public IEnumerable<string> profiles { get; set; }
public IEnumerable<string> certifications { get; set; }
public IEnumerable<string> colors { get; set; }
public IEnumerable<string> specialfittings { get; set; }
public short cutdepths { get; set; }
public string rareness { get; set; }
public class val
{
public String #new { get; set; }
public String used { get; set; }
}
public val value = new val();
public class Pi
{
public Double difficulty { get; set; }
public bool alreadypicked { get; set; }
}
public Pi Picking = new Pi();
public string availableat { get; set; }
public string specialabout { get; set; }
public class devel
{
public string predecessor { get; set; }
public string follower { get; set; }
}
public devel development = new devel();
public Object[] media;
}
}
How to prevent this error ? I just want to deserialize my objects...
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
should be
while (context.Reader.State != BsonReaderState.Type || context.Reader.ReadBsonType() != BsonType.EndOfDocument)
Would cause to check the type if the state is a type. If it is not a type, you will pass and not check the type
Not sure why to use while loop there if you just want to fill properties of one object (description). You can do it like this:
public override Cylinder Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) {
context.Reader.ReadStartDocument();
Cylinder a = new Cylinder();
a.Id = context.Reader.ReadObjectId();
context.Reader.ReadStartDocument();
a.description.type = context.Reader.ReadString();
a.description.kind = context.Reader.ReadString();
a.description.year = (short) context.Reader.ReadInt32();
a.description.producer = context.Reader.ReadString();
return a;
}
Test (File bson.txt is copied verbatim from your question):
static void Main(string[] args) {
var cylinder = new CylinderSerializer().Deserialize(BsonDeserializationContext.CreateRoot(new BsonDocumentReader(BsonDocument.Parse(File.ReadAllText(#"G:\tmp\bson.txt")))));
Console.ReadKey();
}
It's a lot of job to write own serializer this way. This is how i did to for cylinder. I managed to deserialize your sample this way.
Please mention, that there is a one simple help method there to deserialize string array.
You don't have any class for "blaw" data, so i read it in not used variables.
public override Cylinder Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
context.Reader.ReadStartDocument();
Cylinder a = new Cylinder {Id = context.Reader.ReadObjectId()};
context.Reader.ReadStartDocument();
a.description.type = context.Reader.ReadString();
a.description.kind = context.Reader.ReadString();
a.description.year = (short)context.Reader.ReadInt32();
a.description.producer = context.Reader.ReadString();
context.Reader.ReadStartArray();
a.description.brands = new List<string>();
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
{
a.description.brands.Add(context.Reader.ReadString());
}
context.Reader.ReadEndArray();
context.Reader.ReadStartArray();
a.description.model = new Cylinder.mode(new List<string>());
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
{
a.description.model.items.Add(context.Reader.ReadString());
}
context.Reader.ReadEndArray();
a.description.internalproducerdesignation = context.Reader.ReadString();
a.description.origin = context.Reader.ReadString();
context.Reader.ReadEndDocument();
context.Reader.ReadStartDocument();
a.elements = new Cylinder.elem
{
nonspringelements = (short) context.Reader.ReadInt32(),
springelements = (short) context.Reader.ReadInt32(),
discelements = (short) context.Reader.ReadInt32(),
magneticelements = (short) context.Reader.ReadInt32(),
activeelements = (short) context.Reader.ReadInt32(),
passiveelements = (short) context.Reader.ReadInt32(),
totalelements = (short) context.Reader.ReadInt32()
};
context.Reader.ReadEndDocument();
a.profiles = readStringArray(context);
a.certifications = readStringArray(context);
a.colors = readStringArray(context);
a.specialfittings = readStringArray(context);
a.cutdepths = (short) context.Reader.ReadInt32();
a.rareness = context.Reader.ReadString();
context.Reader.ReadStartDocument();
a.value = new Cylinder.val
{
#new = context.Reader.ReadString(),
used = context.Reader.ReadString()
};
context.Reader.ReadEndDocument();
context.Reader.ReadStartDocument();
var blawInt = context.Reader.ReadDouble();
var blawBool = context.Reader.ReadBoolean();
context.Reader.ReadEndDocument();
a.availableat = context.Reader.ReadString();
a.specialabout = context.Reader.ReadString();
context.Reader.ReadStartDocument();
a.development = new Cylinder.devel
{
predecessor = context.Reader.ReadString(),
follower = context.Reader.ReadString()
};
context.Reader.ReadEndDocument();
var objects=new List<object>();
context.Reader.ReadStartArray();
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
{
objects.Add(context.Reader.ReadString());
}
context.Reader.ReadEndArray();
a.media = objects.ToArray();
context.Reader.ReadEndDocument();
return a;
}
private static IEnumerable<string> readStringArray(BsonDeserializationContext context)
{
context.Reader.ReadStartArray();
var strings = new List<string>();
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
{
strings.Add(context.Reader.ReadString());
}
context.Reader.ReadEndArray();
return strings;
}
I'm trying to use a custom singlearrayconverter to access the values of my json array, but I keep getting null values, I'm wondering where I could be doing something wrong.
I have the following JSON:
{
"message": "success",
"action": "user_info",
"data": {
"profile_info": {
"querying": "0",
"tps": {
"1": {
"profile_url": "anotherfakeurl",
"file_hash": "hash",
"icon_path": "",
"time_of_insertion": "0000-00-00 00:00:00",
"tp_id": "1",
"user_id": "4",
"tp_user_id": "1377839182243200",
"last_use": "0000-00-00 00:00:00",
"active": "0",
"user_display": "it's a me",
"selected": "1",
"prof_pic": "fakeurl"
}
}
}
}
}
And I have the following datamodel:
[JsonProperty("tps")]
[JsonConverter(typeof(SingleValueArrayConverter<Tps>))]
public List<Tps> TpsList { get; set; }
And I'm using this converter:
public class SingleValueArrayConverter<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)
{
object retVal = new Object();
if (reader.TokenType == JsonToken.StartObject)
{
T instance = (T)serializer.Deserialize(reader, typeof(T));
retVal = new List<T>() { instance };
}
else if (reader.TokenType == JsonToken.StartArray)
{
retVal = serializer.Deserialize(reader, objectType);
}
return retVal;
}
public override bool CanConvert(Type objectType)
{
return false;
}
}
And every other value is correct, it even gives me the right array count. But the contents of each Tps property are either empty or null.
Thank you,
edit: Here is the full Data Model.
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class UserInfo
{
[JsonProperty("message")]
public string Message { get; set; }
[JsonProperty("action")]
public string Action { get; set; }
[JsonProperty("data")]
public Data Data { get; set; }
}
public class Data
{
[JsonProperty("profile_info")]
public ProfileInformation ProfileInformation { get; set; }
}
public class ProfileInformation
{
[JsonProperty("querying")]
public string Querying { get; set; }
[JsonProperty("tps")]
[JsonConverter(typeof(SingleValueArrayConverter<Tps>))]
public List<Tps> TpsList { get; set; }
}
public class Tps
{
[JsonProperty("profile_url")]
public string ProfileUrl { get; set; }
[JsonProperty("file_hash")]
public string FileHash { get; set; }
[JsonProperty("icon_path")]
public string IconPath { get; set; }
[JsonIgnore]
[JsonProperty("time_of_insertion")]
public DateTime TimeOfInsertion { get; set; }
[JsonProperty("tp_id")]
public int TpId { get; set; }
[JsonProperty("user_id")]
public int UserId { get; set; }
[JsonProperty("tp_user_id")]
public long TpUserId { get; set; }
[JsonIgnore]
[JsonProperty("last_use")]
public DateTime LastUse { get; set; }
[JsonProperty("active")]
public string Active { get; set; }
[JsonProperty("user_display")]
public string UserDisplay { get; set; }
[JsonProperty("selected")]
public string Selected { get; set; }
[JsonProperty("prof_pic")]
public string ProfilePicture { get; set; }
}
I am not saying this is the most elegant or best way around, but it works. You can use a dictionary to achieve the desired bahavior. So, lose the converter, then move back and forth between a list and a dictionary, key being that TpId field it seems.
public class ProfileInformation
{
[JsonProperty("querying")]
public string Querying { get; set; }
List<Tps> _tpsList = null;
[JsonIgnore]
public List<Tps> TpsList {
get {
if (_tpsList == null && _tpsDict != null) {
_tpsList = _tpsDict.Values.ToList();
}
return _tpsList;
}
set { _tpsList = value; }
}
Dictionary<int, Tps> _tpsDict = null;
[JsonProperty("tps")]
public Dictionary<int, Tps> TpsDict {
get {
if (_tpsDict == null && _tpsList != null) {
_tpsDict = _tpsList.ToDictionary(x => x.TpId);
}
return _tpsDict;
}
set { _tpsDict = value; }
}
}
Test
var userInfo = new UserInfo() {
Action = "user_info",
Message = "success",
Data = new Data() {
ProfileInformation = new ProfileInformation() {
Querying = "0",
TpsList = new List<Tps>() {
new Tps() {
Active="0",
FileHash = "hash",
IconPath="",
LastUse= DateTime.MinValue,
ProfileUrl = "anotherfakeurl",
ProfilePicture = "fakeurl",
Selected = "1",
TimeOfInsertion = DateTime.MinValue,
TpId = 1,
TpUserId = 1377839182243200L,
UserDisplay = "it's a me",
UserId = 4
} } } } };
string json = JsonConvert.SerializeObject(userInfo, Formatting.Indented);
var newUserInfo = JsonConvert.DeserializeObject<UserInfo> (json);
Assert.AreEqual(newUserInfo.Data.ProfileInformation.TpsList.Count,1);
Assert.AreEqual(newUserInfo.Data.ProfileInformation.TpsDict.Count,1);
I have some JSON that can come in two different formats. Sometimes the location value is a string, and sometimes it is an object. This is a sample of the first format:
{
"result": [
{
"upon_approval": "Proceed to Next Task",
"location": "",
"expected_start": ""
}
]
}
Class definitions for this:
public class Result
{
public string upon_approval { get; set; }
public string location { get; set; }
public string expected_start { get; set; }
}
public class RootObject
{
public List<Result> result { get; set; }
}
Here is the JSON in the second format:
{
"result": [
{
"upon_approval": "Proceed to Next Task",
"location": {
"display_value": "Corp-HQR",
"link": "https://satellite.service-now.com/api/now/table/cmn_location/4a2cf91b13f2de00322dd4a76144b090"
},
"expected_start": ""
}
]
}
Class definitions for this:
public class Location
{
public string display_value { get; set; }
public string link { get; set; }
}
public class Result
{
public string upon_approval { get; set; }
public Location location { get; set; }
public string expected_start { get; set; }
}
public class RootObject
{
public List<Result> result { get; set; }
}
When deserializing, I get errors when the JSON format does not match my classes, but I don't know ahead of time which classes to use because the JSON format changes. So how can I dynamically get these two JSON formats to deserialize into one set of classes?
This is how I am deserializing now:
JavaScriptSerializer ser = new JavaScriptSerializer();
ser.MaxJsonLength = 2147483647;
RootObject ro = ser.Deserialize<RootObject>(responseValue);
To solve this problem you'll need to make a custom JavaScriptConverter class and register it with the serializer. The serializer will load the result data into a Dictionary<string, object>, then hand off to the converter, where you can inspect the contents and convert it into a usable object. In short, this will allow you to use your second set of classes for both JSON formats.
Here is the code for the converter:
class ResultConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get { return new List<Type> { typeof(Result) }; }
}
public override object Deserialize(IDictionary<string, object> dict, Type type, JavaScriptSerializer serializer)
{
Result result = new Result();
result.upon_approval = GetValue<string>(dict, "upon_approval");
var locDict = GetValue<IDictionary<string, object>>(dict, "location");
if (locDict != null)
{
Location loc = new Location();
loc.display_value = GetValue<string>(locDict, "display_value");
loc.link = GetValue<string>(locDict, "link");
result.location = loc;
}
result.expected_start = GetValue<string>(dict, "expected_start");
return result;
}
private T GetValue<T>(IDictionary<string, object> dict, string key)
{
object value = null;
dict.TryGetValue(key, out value);
return value != null && typeof(T).IsAssignableFrom(value.GetType()) ? (T)value : default(T);
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
}
Then use it like this:
var ser = new JavaScriptSerializer();
ser.MaxJsonLength = 2147483647;
ser.RegisterConverters(new List<JavaScriptConverter> { new ResultConverter() });
RootObject ro = serializer.Deserialize<RootObject>(responseValue);
Here is a short demo:
class Program
{
static void Main(string[] args)
{
string json = #"
{
""result"": [
{
""upon_approval"": ""Proceed to Next Task"",
""location"": {
""display_value"": ""Corp-HQR"",
""link"": ""https://satellite.service-now.com/api/now/table/cmn_location/4a2cf91b13f2de00322dd4a76144b090""
},
""expected_start"": """"
}
]
}";
DeserializeAndDump(json);
Console.WriteLine(new string('-', 40));
json = #"
{
""result"": [
{
""upon_approval"": ""Proceed to Next Task"",
""location"": """",
""expected_start"": """"
}
]
}";
DeserializeAndDump(json);
}
private static void DeserializeAndDump(string json)
{
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new List<JavaScriptConverter> { new ResultConverter() });
RootObject obj = serializer.Deserialize<RootObject>(json);
foreach (var result in obj.result)
{
Console.WriteLine("upon_approval: " + result.upon_approval);
if (result.location != null)
{
Console.WriteLine("location display_value: " + result.location.display_value);
Console.WriteLine("location link: " + result.location.link);
}
else
Console.WriteLine("(no location)");
}
}
}
public class RootObject
{
public List<Result> result { get; set; }
}
public class Result
{
public string upon_approval { get; set; }
public Location location { get; set; }
public string expected_start { get; set; }
}
public class Location
{
public string display_value { get; set; }
public string link { get; set; }
}
Output:
upon_approval: Proceed to Next Task
location display_value: Corp-HQR
location link: https://satellite.service-now.com/api/now/table/cmn_location/4a2cf91b13f2de00322dd4a76144b090
----------------------------------------
upon_approval: Proceed to Next Task
(no location)
I am trying to deserialize the json string from Rest webserive in C#. Following is jsonstring and classes I used. But after deserialize it is giving null/empty value on server.But in local its working as expected. So what's going wrong with me?
Json String
{
"error": false,
"parameters": [
{
"Programs": "ZZ_UNUSED_EU-01pp-Q669;EU-PPP-O003;ZZ_UNUSED_EU-PPP-CO05;100000;pbse;EU-m110-2007;EU-zz33-L053;EU-zz21-z084;ZZ_UNUSED_EU-01pp-Q875;EU-zz05-L029;ZZ_UNUSED_EU-RAD-003;ZZ_UNUSED_EU-RAD-004;ZZ_UNUSED_EU-RAD-007;ZZ_UNUSED_EU-RAD-012;ZZ_UNUSED_EU-RAD-015;ZZ_UNUSED_EU-zz22-RF21;ZZ_UNUSED_EU-PPP-CO130;ZZ_UNUSED_EU-01pp-Q962;ZZ_UNUSED_EU-01pp-Q963;EU-LandR-COM;EU-01pp-O960;EU-SI-HP-INTL;G_PC_SQ;G_Survey_Inv_TPE-FY11;G_MADO_3Com;G_eLocator_AIS;G_eLocator_ATP;G_eLocator_SCE;G_eLocator_TECI;G_L&R_SCREENED;G_L&R_CASE_OPEN;EU-MDF-Tool;EU-DI-SPT-FLASHPRO;EU-DI-SPT-FLASHPRO-FY11;EU-DI-SPT-FLASHPRO-FY12;G_SPT_PCLM_Prospect;G_SPT_PCLM_Enrolled;SPEC_P1_S1_GOLD_PPS_CAN;G_SPT_Joint_Business_Planning;EU_RET_CE_SCOPE;G_PARTNER_HPQ;ZZ_UNUSED_EU-01pp-O972;SPEC_P1_SERV_SILV_CAN;SPEC_P1_STOR_SILV_CAN;SPEC_P1_NW_SILV_CAN;SPEC_P1_S1_SILV_CAN;PM_P1_PLAT_PART_CAN;PM_P1_SILV_PART_PPS_SM_CAN;SPEC_P1_WK_GOLD_CAN;ZZ_UNUSED_EU-01pp-Q018;"
},
{
"PartnerSubTypes": "G_Tgt_Commercial_T2_Reseller_S;SSP;Supplies Commercial;"
},
{
"CompanyNumber": "29682"
},
{
"PartnerNameHQ": "151070026"
},
{
"SiteIdentifier": "UPP"
},
{
"LastName": "Isaksson"
},
{
"HPInternalUser": "F"
},
{
"PhysAdLine1": "?STRA HAMNEN 1"
},
{
"HPPUserId": "989d35449261b4348e2f477260b1eacc"
},
{
"PartnerName": "Misco AB"
},
{
"PhysAdLine2": ""
},
{
"PhysAdLine3": ""
},
{
"PrimaryChannelSegment": "TDL"
},
{
"HPOrg": "HP Sweden"
},
{
"LastLoginDate": "1426841482160"
},
{
"PartnerPhone": ""
},
{
"PartnerLegalName": "Misco AB"
},
{
"HPOrgs": "Default Organization;HP Sweden;"
},
{
"FirstName": "Joakim"
},
{
"CountryCode": "SE"
},
{
"PreferredLanguageCode": "en"
},
{
"IsPartnerAdmin": "T"
},
{
"PartnerProIdHQ": "1-2GF-564"
},
{
"Accreditations": "G_PM_P1_PLAT_PAR_PP_BU;G_SEGT_EG_SERV_GROWTH;G_SEGT_EG_TS_GROWTH;G_FC_AGR_T2;G_S1_Prospect;G_GPL_P1_PPS_SM;ZZ_UNUSED_EU-zz46-c103;EU-02pp-O138;G_P1_Specialist_Enrolled;G_P1_Specialist_Candidate;G_S1_EXP;G_GPL_P1_EG_BUS;G_GPL_P1_PPS;G_PM_P1_PLAT_PAR;G_PM_P1_BUS_SP_EG_BU;G_GPL_P1_WK;G_P1_Preferred_Candidate;G_P1_Specialist_Enrolled;G_S1_Candidate;G_SEGT_PAN-EG_GROWTH;G_SEGT_EG_NW_GROWTH;G_SEGT_EG_STOR_GROWTH;FY15_P1_STOR_SILV_TGT;FY15_P1_S1_SILV_TGT;FY15_P1_NW_SILV_TGT;G_GPL_P1_S1_P;G_S1_Prospect;FY15_P1_SERV_SILV_TGT;G_PM_P1_BUS_SP_EG;G_PM_P1_PLAT_PAR_PP;G_PM_P1_SILV_PAR_PP_SM;G_SPEC_P1_S1_GOLD_P;G_SPEC_P1_WK_GOLD;ZZ_UNUSED_EU-I&P;ZZ_UNUSED_EU-01pp-Q586;"
},
{
"PhysCountry": "Sweden"
},
{
"PhysCity": "LIDK?PING"
},
{
"PartnerProId": "1-2GF-564"
},
{
"Tier": ""
},
{
"Email": "itg.itg.joakim.isaksson#misco.se"
},
{
"PhysPostalCode": "531 40"
},
{
"PartnerFax": ""
}
]
}
Rest webservice call
//string requestUrl = "http://localhost:8080/RestWSPartner/parameter";
string requestUrl = "https://upp-itg-moonshot-gslb.austin.hp.com/delegate/esmtokenvalidation/v1?token="+tokenId;
Log.WriteInfo("requestUrl in RestWS==>" + requestUrl);
do
{
HttpWebRequest request = HttpWebRequest.Create(requestUrl) as HttpWebRequest;
request.Method = "GET";
request.ContentType = "application/json; charset=UTF-8";//charset=UTF-8";
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(PartnerData));
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
Stream receiveStream = response.GetResponseStream();
restResponse = jsonSerializer.ReadObject(receiveStream) as PartnerData;
Log.WriteInfo("restResponse.error ==>" + restResponse.error);
Log.WriteInfo("restResponse.message ==>" + restResponse.message);
if (restResponse.error.Equals("false"))
{
// Log.WriteInfo("restResponse===UserId>" + restResponse.parameters.HPPUserId);
Log.WriteInfo("restResponse===PartnerProId>" + restResponse.parameters.PreferredLanguageCode);
Log.WriteInfo("restResponse===PartnerProId>" + restResponse.parameters.FirstName);
Log.WriteInfo("success.. Break");
break;
}
my class
namespace ProductguideNordic
{
[DataContract]
public class PartnerData
{
[DataMember(Name = "error")]
public string error { get; set; }
[DataMember(Name = "message")]
public string message { get; set; }
[DataMember(Name = "parameters")]
public Paramter parameters { get; set; }
}
[DataContract]
public class Paramter
{
[DataMember(Name = "Programs")]
public string Programs { set; get; }
[DataMember(Name = "PartnerSubTypes")]
public string PartnerSubTypes { set; get; }
[DataMember(Name = "CompanyNumber")]
public string CompanyNumber { set; get; }
[DataMember(Name = "PartnerNameHQ")]
public string PartnerNameHQ { set; get; }
[DataMember(Name = "SiteIdentifier")]
public string SiteIdentifier { set; get; }
[DataMember(Name = "LastName")]
public string LastName { set; get; }
[DataMember(Name = "HPInternalUser")]
public string HPInternalUser { set; get; }
[DataMember(Name = "PhysAdLine1")]
public string PhysAdLine1 { set; get; }
[DataMember(Name = "HPPUserId")]
public string HPPUserId { set; get; }
[DataMember(Name = "PartnerName")]
public string PartnerName { set; get; }
[DataMember(Name = "PhysAdLine2")]
public string PhysAdLine2 { set; get; }
[DataMember(Name = "PhysAdLine3")]
public string PhysAdLine3 { set; get; }
[DataMember(Name = "PrimaryChannelSegment")]
public string PrimaryChannelSegment { set; get; }
[DataMember(Name = "HPOrg")]
public string HPOrg { set; get; }
[DataMember(Name = "LastLoginDate")]
public string LastLoginDate { set; get; }
[DataMember(Name = "PartnerPhone")]
public string PartnerPhone { set; get; }
[DataMember(Name = "PartnerLegalName")]
public string PartnerLegalName { set; get; }
[DataMember(Name = "HPOrgs")]
public string HPOrgs { set; get; }
[DataMember(Name = "FirstName")]
public string FirstName { set; get; }
[DataMember(Name = "CountryCode")]
public string CountryCode { set; get; }
[DataMember(Name = "PreferredLanguageCode")]
public string PreferredLanguageCode { set; get; }
[DataMember(Name = "IsPartnerAdmin")]
public string IsPartnerAdmin { set; get; }
[DataMember(Name = "PartnerProIdHQ")]
public string PartnerProIdHQ { set; get; }
[DataMember(Name = "Accreditations")]
public string Accreditations { set; get; }
[DataMember(Name = "PhysCountry")]
public string PhysCountry { set; get; }
[DataMember(Name = "physCity")]
public string physCity { set; get; }
[DataMember(Name = "PartnerProId")]
public string PartnerProId { set; get; }
[DataMember(Name = "Tier")]
public string Tier { set; get; }
[DataMember(Name = "Email")]
public string Email { set; get; }
[DataMember(Name = "PhysPostalCode")]
public string PhysPostalCode { set; get; }
[DataMember(Name = "PartnerFax")]
public string PartnerFax { set; get; }
[DataMember(Name = "PortalSessionId")]
public string PortalSessionId { set; get; }
}
}
In my local with local URL, im able to deserialize the json string and assigned to partnerdata. In server (windows 2012) after deployed into IIS(8.5) parameters values are null/ empty and there was no error while deserialize . Rest WS sending expected response's. and restResponse.error this value deserialized correctly but parameters are not deserialized.
So what's going wrong with me?
In the JSON string you show, "parameters" is an array of name/value pairs:
{
"error": false,
"parameters": [
{
"Programs": "ZZ_UNUSED_EU-01pp-Q669;EU-PPP-O003;ZZ_UNUSED_EU-PPP-CO05;100000;pbse;EU-m110-2007;EU-zz33-L053;EU-zz21-z084;ZZ_UNUSED_EU-01pp-Q875;EU-zz05-L029;ZZ_UNUSED_EU-RAD-003;ZZ_UNUSED_EU-RAD-004;ZZ_UNUSED_EU-RAD-007;ZZ_UNUSED_EU-RAD-012;ZZ_UNUSED_EU-RAD-015;ZZ_UNUSED_EU-zz22-RF21;ZZ_UNUSED_EU-PPP-CO130;ZZ_UNUSED_EU-01pp-Q962;ZZ_UNUSED_EU-01pp-Q963;EU-LandR-COM;EU-01pp-O960;EU-SI-HP-INTL;G_PC_SQ;G_Survey_Inv_TPE-FY11;G_MADO_3Com;G_eLocator_AIS;G_eLocator_ATP;G_eLocator_SCE;G_eLocator_TECI;G_L&R_SCREENED;G_L&R_CASE_OPEN;EU-MDF-Tool;EU-DI-SPT-FLASHPRO;EU-DI-SPT-FLASHPRO-FY11;EU-DI-SPT-FLASHPRO-FY12;G_SPT_PCLM_Prospect;G_SPT_PCLM_Enrolled;SPEC_P1_S1_GOLD_PPS_CAN;G_SPT_Joint_Business_Planning;EU_RET_CE_SCOPE;G_PARTNER_HPQ;ZZ_UNUSED_EU-01pp-O972;SPEC_P1_SERV_SILV_CAN;SPEC_P1_STOR_SILV_CAN;SPEC_P1_NW_SILV_CAN;SPEC_P1_S1_SILV_CAN;PM_P1_PLAT_PART_CAN;PM_P1_SILV_PART_PPS_SM_CAN;SPEC_P1_WK_GOLD_CAN;ZZ_UNUSED_EU-01pp-Q018;"
},
{
"PartnerSubTypes": "G_Tgt_Commercial_T2_Reseller_S;SSP;Supplies Commercial;"
},
Your code is attempting to deserialize parameters as a single object with many properties, e.g.:
{
"error": false,
"parameters": {
"Programs": "ZZ_UNUSED_EU-01pp-Q669;EU-PPP-O003;ZZ_UNUSED_EU-PPP-CO05;100000;pbse;EU-m110-2007;EU-zz33-L053;EU-zz21-z084;ZZ_UNUSED_EU-01pp-Q875;EU-zz05-L029;ZZ_UNUSED_EU-RAD-003;ZZ_UNUSED_EU-RAD-004;ZZ_UNUSED_EU-RAD-007;ZZ_UNUSED_EU-RAD-012;ZZ_UNUSED_EU-RAD-015;ZZ_UNUSED_EU-zz22-RF21;ZZ_UNUSED_EU-PPP-CO130;ZZ_UNUSED_EU-01pp-Q962;ZZ_UNUSED_EU-01pp-Q963;EU-LandR-COM;EU-01pp-O960;EU-SI-HP-INTL;G_PC_SQ;G_Survey_Inv_TPE-FY11;G_MADO_3Com;G_eLocator_AIS;G_eLocator_ATP;G_eLocator_SCE;G_eLocator_TECI;G_L&R_SCREENED;G_L&R_CASE_OPEN;EU-MDF-Tool;EU-DI-SPT-FLASHPRO;EU-DI-SPT-FLASHPRO-FY11;EU-DI-SPT-FLASHPRO-FY12;G_SPT_PCLM_Prospect;G_SPT_PCLM_Enrolled;SPEC_P1_S1_GOLD_PPS_CAN;G_SPT_Joint_Business_Planning;EU_RET_CE_SCOPE;G_PARTNER_HPQ;ZZ_UNUSED_EU-01pp-O972;SPEC_P1_SERV_SILV_CAN;SPEC_P1_STOR_SILV_CAN;SPEC_P1_NW_SILV_CAN;SPEC_P1_S1_SILV_CAN;PM_P1_PLAT_PART_CAN;PM_P1_SILV_PART_PPS_SM_CAN;SPEC_P1_WK_GOLD_CAN;ZZ_UNUSED_EU-01pp-Q018;"
"PartnerSubTypes": ""G_Tgt_Commercial_T2_Reseller_S;SSP;Supplies Commercial;""
In other words, the JSON you are receiving for "parameters"corresponds to a List<Dictionary<string, string>> with UseSimpleDictionaryFormat = false, rather than a single POCO with various properties.
Update
Given that this is a legacy application using an older version of .Net (possibly with some configuration issues, as the var keyword is causing you to have a compiler error), I am going to suggest switching to JavaScriptSerializer which is also a built-in .Net component. Change your data model as follows:
public class PartnerDataDictionary
{
public PartnerDataDictionary()
{
this.ParameterDictionary = new Dictionary<string, string>();
}
string _error;
public string error { get { return _error; } set { _error = value; } }
string _message;
public string message { get { return _message; } set { _message = value; } }
[System.Web.Script.Serialization.ScriptIgnore]
public Dictionary<string, string> ParameterDictionary { get; set; }
public List<Dictionary<string, string>> parameters
{
get
{
List<Dictionary<string, string>> dictList = new List<Dictionary<string, string>>();
foreach (KeyValuePair<string, string> pair in ParameterDictionary)
{
Dictionary<string, string> subDict = new Dictionary<string,string>(1);
subDict[pair.Key] = pair.Value;
dictList.Add(subDict);
}
return dictList;
}
set
{
if (value == null)
{
ParameterDictionary = new Dictionary<string, string>();
return;
}
Dictionary<string, string> dict = new Dictionary<string, string>();
foreach (Dictionary<string, string> entry in value)
foreach (KeyValuePair<string, string> pair in entry)
dict.Add(pair.Key, pair.Value);
ParameterDictionary = dict;
}
}
public string GetParameter(string key)
{
string value;
if (ParameterDictionary.TryGetValue(key, out value))
return value;
return null;
}
public void SetParameter(string key, string value)
{
ParameterDictionary[key] = value;
}
// Add other properties as needed, marking them as `ScriptIgnore`:
[System.Web.Script.Serialization.ScriptIgnore]
public string Programs
{
get { return GetParameter("Programs"); }
set { SetParameter("Programs", value); }
}
}
What I am doing here is reading the JSON as a list of dictionaries, then combining them into a dictionary in the setter for ease of use.
Then you can read and write your JSON parameters as follows:
PartnerDataDictionary data = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<PartnerDataDictionary>(json);
string programs = data.Programs;
Debug.WriteLine(programs);
Original Answer
You could simply change your PartnerData class to have such a list of dictionaries. If you want to continue to use your current data model, and also use DataContractJsonSerializer, you are going to need to introduce a data contract surrogate to do the conversion:
public class ObjectToPropertyDictionaryArraySurrogate<T> : IDataContractSurrogate
{
class ListDictionaryArray : List<Dictionary<string, string>>
{
}
#region IDataContractSurrogate Members
public object GetCustomDataToExport(Type clrType, Type dataContractType)
{
throw new NotImplementedException();
}
public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
{
throw new NotImplementedException();
}
public Type GetDataContractType(Type type)
{
if (type == typeof(T))
return typeof(ListDictionaryArray);
return type;
}
public object GetDeserializedObject(object obj, Type targetType)
{
if (obj is ListDictionaryArray)
{
var array = (ListDictionaryArray)obj;
var dict = array.SelectMany(pair => pair).ToDictionary(pair => pair.Key, pair => pair.Value);
var json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(dict);
return DataContractJsonSerializerHelper.GetObject<T>(json, new DataContractJsonSerializerSettings { UseSimpleDictionaryFormat = true });
}
return obj;
}
public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
{
throw new NotImplementedException();
}
public object GetObjectToSerialize(object obj, Type targetType)
{
if (obj.GetType() == typeof(T))
{
var json = DataContractJsonSerializerHelper.GetJson((T)obj, new DataContractJsonSerializerSettings { UseSimpleDictionaryFormat = true });
var dict = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<Dictionary<string, string>>(json);
var array = new ListDictionaryArray();
array.AddRange(dict.Select(pair => new[] { pair }.ToDictionary(p => p.Key, p => p.Value)));
return array;
}
return obj;
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
{
throw new NotImplementedException();
}
public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
{
throw new NotImplementedException();
}
#endregion
}
public static class DataContractJsonSerializerHelper
{
public static string GetJson<T>(T obj, DataContractJsonSerializer serializer)
{
using (var memory = new MemoryStream())
{
serializer.WriteObject(memory, obj);
memory.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(memory))
{
return reader.ReadToEnd();
}
}
}
public static string GetJson<T>(T obj)
{
var serializer = new DataContractJsonSerializer(typeof(T));
return GetJson(obj, serializer);
}
public static string GetJson<T>(T obj, DataContractJsonSerializerSettings settings)
{
var serializer = new DataContractJsonSerializer(obj.GetType(), settings);
return GetJson<T>(obj, serializer);
}
public static T GetObject<T>(string json, DataContractJsonSerializer serializer)
{
using (var stream = GenerateStreamFromString(json))
{
var obj = serializer.ReadObject(stream);
return (T)obj;
}
}
public static T GetObject<T>(string json)
{
var serializer = new DataContractJsonSerializer(typeof(T));
return GetObject<T>(json, serializer);
}
public static T GetObject<T>(string json, DataContractJsonSerializerSettings settings)
{
var serializer = new DataContractJsonSerializer(typeof(T), settings);
return GetObject<T>(json, serializer);
}
private static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
}
}
And then use it like:
var settings = new DataContractJsonSerializerSettings
{
UseSimpleDictionaryFormat = true,
DataContractSurrogate = new ObjectToPropertyDictionaryArraySurrogate<Paramter>(),
};
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(PartnerData), settings);