Create Json Array with ServiceStack - c#

Quite new to .NET. Still haven't gotten the hang of how to do dictionaries, lists, arrays, etc.
I need to produce this JSON in order to talk to SugarCRM's REST API:
{
"name_value_list": {
"assigned_user_name": {
"name": "assigned_user_name",
"value": "joe"
},
"modified_by_name": {
"name": "modified_by_name",
"value": "jill"
},
"created_by_name": {
"name": "created_by_name",
"value": "jack"
}
}
}
from this C# POCO, which plays nicely with ServiceStack:
public class lead {
public string assigned_user_name { get; set; }
public string modified_by_name { get; set; }
public string created_by_name { get; set; }
}
I have to do this sort of conversion for lots of different classes, so I don't think it's wise to create another strongly typed class (ala Costomising the serialisation/serialised JSON in service stack)
I've looked through the ServiceStack docs, but maybe I missed an example of this somewhere.
How do I build this JSON in a way that I can extend to other ServiceStack POCOs?

This produces the right JSON:
Dictionary<string, Dictionary<string, string>> nameValues = new Dictionary<string, Dictionary<string, string>>();
// Deal with all the properties on the object
IList<PropertyInfo> props = new List<PropertyInfo>(this.GetType().GetProperties());
foreach (PropertyInfo prop in props)
{
Dictionary<string, string> nameValue = new Dictionary<string, string>();
nameValue.Add("name", prop.Name);
object propValue = prop.GetValue(this, null);
if (propValue == null)
{
nameValue.Add("value", string.Empty);
}
else
{
nameValue.Add("value", prop.GetValue(this, null).ToString());
}
nameValues.Add(prop.Name, nameValue);
}
Dictionary<string, object> nameValuesArray = new Dictionary<string, object>();
nameValuesArray.Add("name_value_list", nameValues);
string jsonString = JsonSerializer.SerializeToString<Dictionary<string, object>>(nameValuesArray);
The reflection stuff is so that I can use it on any object later.
It's just a matter of constructing the right dictionary for the desired JSON output - in this case a dictionary -> dictionary -> dictionary. Trial and error... :/
Update
Altered it slightly (thanks paaschpa) to use a generic NameValue class because Dictionaries look ugly. I also got the requirements wrong. The JSON should be this:
[
{
"name": "id",
"value": "60e03cb3-df91-02bd-91ae-51cb04f937bf"
},
{
"name": "first_name",
"value": "FancyPants"
}
]
which you can do like this:
public class NameValue
{
public string name { get; set; }
public string value { get; set; }
}
public class Lead
{
public string assigned_user_name { get; set; }
public string modified_by_name { get; set; }
public string modified_user_name { get; set; }
public List<NameValue> toNameValues()
{
List<NameValue> nameValues = new List<NameValue>();
IList<PropertyInfo> props = new List<PropertyInfo>(this.GetType().GetProperties());
foreach (PropertyInfo prop in props)
{
NameValue nameValue = new NameValue();
object propValue = prop.GetValue(this, null);
if (propValue != null && !String.IsNullOrEmpty(propValue.ToString()))
{
nameValue.name = prop.Name;
nameValue.value = propValue.ToString();
nameValues.Add(nameValue);
}
}
return nameValues;
}
}
I'm leaving my original question as is (and my above answer) because it's still a legit example and proper JSON.

Well, I don't think .NET dictionaries, lists, arrays, etc. will be helpful since the JSON you listed doesn't appear to have any arrays (square brackets) it in. I'm guessing most .NET JSON serializers will use square brackets when it hits these types. So, I think this leaves creating your own classes or doing some type of 'string magic' to produce to JSON you need.
Not exactly sure how you are using ServiceStack to talk to SugarCRM, but doing something like below should have ServiceStack.Text.JsonSerializer produce the JSON string you listed.
public class NameValue
{
public string name { get; set; }
public string value { get; set; }
}
public class Lead
{
public NameValue assigned_user_name { get; set; }
public NameValue modified_by_name { get; set; }
public NameValue created_by_name { get; set; }
}
public class LeadRequest
{
public Lead name_value_list { get; set; }
}
public void JsonTest()
{
var req = new LeadRequest
{
name_value_list = new Lead
{
assigned_user_name = new NameValue {name = "assigned_user_name", value = "joe"},
modified_by_name = new NameValue {name = "modified_by_name", value = "jill"},
created_by_name = new NameValue {name = "created_by_name", value = "jack"}
}
};
var jsonReq = ServiceStack.Text.JsonSerializer.SerializeToString(req);
}

You could create a custom serializer for the lead class.
JsConfig<lead>.SerializeFn = lead => {
// Use reflection to loop over the properties of the `lead` object and build a dictionary
var data = new Dictionary<string, object>();
foreach (var property in typeof(lead).GetProperties()) {
data[property.Name] = new {
name: property.Name,
value: property.GetValue(lead, null);
};
}
return data.ToJson();
};
You could make this generic by having all classes that you want to serialize in this way implement a marker interface, for example ISugarCrmRequest, and register this custom serializer for all implementations of that interface.

Related

System.Text.Json.JsonSerializer.Serialize adds \u0022

How can I set JsonSerializer to not add "\u0022" to string for EventData property? Because I get:
{"Id":5,"CreateDate":"2021-04-21T05:26:30.9817284Z","EventData":"{\u0022Id\u0022:1,\u0022Email\u0022:\u0022test#test.test\u0022}"}
I will never deserialize EventData, it must be readable. And I want:
{"Id":5,"CreateDate":"2021-04-21T05:26:30.9817284Z","EventData":"{Id:1,Email:test#test.test}"}
My code:
public class EmailSent
{
public int Id { get; set; }
public string Email { get; set; }
}
public class UserCreated
{
public int Id { get; set; }
public DateTime CreateDate { get; set; }
public string EventData { get; set; }
}
var emailSent = new EmailSent
{
Id = 1,
Email = "test#test.test"
};
var userCreated = new UserCreated
{
Id = 5,
CreateDate = DateTime.UtcNow,
EventData = JsonSerializer.Serialize(emailSent) // I will never deserialize it
};
string result = JsonSerializer.Serialize(userCreated);
You can use, for example, UnsafeRelaxedJsonEscaping:
var serializeOptions = new JsonSerializerOptions
{
WriteIndented = true,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
string json = JsonSerializer.Serialize(userCreated, serializeOptions);
This will produce the following output:
{
"Id": 5,
"CreateDate": "2021-04-21T07:49:23.4378969Z",
"EventData": "{\"Id\":1,\"Email\":\"test#test.test\"}"
}
Reference: How to customize character encoding with System.Text.Json. Please read the caution there:
Caution
Compared to the default encoder, the UnsafeRelaxedJsonEscaping encoder is more permissive about allowing characters to pass through unescaped:
(...)
This happens because JsonSerializer.Serialize() is invoked more than once.
You can specify 'JSONSerializerOptions' Encoder equal to JavaScriptTenCoder. Create(new TextEncoderSettings(UnicodeRanges.All))
like this
public static string ToString(this object str)
{
try
{
string sResult = JsonSerializer.Serialize(str, new JsonSerializerOptions{WriteIndented = true, Encoder = JavaScriptEncoder.Create(new TextEncoderSettings(System.Text.Unicode.UnicodeRanges.All))});
return sResult;
}
}
I have almost the exact same problem, only my UserCreated is being returned by ASP.NET controller function, I don't directly control serialization.
The simplest solution is to change the type of EventData to JsonNode.
To set EventData from whatever complex object you want, you can use this awkward construct
EventData = JsonNode.Parse(JsonSerializer.Serialize(complexData))
Complete minimal example:
[Test]
public void Test1()
{
Dictionary<string, string> complexData =
new Dictionary<string, string>() { { "A", "B" } };
NestedJason toSerialize = new NestedJason()
{
FormName = "String",
FormData = JsonNode.Parse(JsonSerializer.Serialize(complexData))
};
Console.WriteLine(JsonSerializer.Serialize(toSerialize));
// prints {"FormName":"String","FormData":{"A":"B"}}
}
}
public class NestedJason
{
public string FormName { get; set; }
public JsonNode FormData { get; set; }
}
A cleaner option is to make FormData type object. (I'm assuming you don't want to make it type EmailSent because you want to store random data about many different types of events.) If you round trip the EventData as object, it will go in as EmailSent and come back out as JsonElement. Manual steps would be required to get it back to an EmailSent.
public class Tests
{
[Test]
public void Test1()
{
Dictionary<string, string> complexData =
new Dictionary<string, string>() { { "A", "B" } };
NestedJason toSerialize = new NestedJason()
{
FormName = "Sting",
FormData = complexData
};
Console.WriteLine(JsonSerializer.Serialize(toSerialize));
NestedJason result = JsonSerializer.Deserialize(
JsonSerializer.Serialize(toSerialize),
typeof(NestedJason)) as NestedJason;
Console.WriteLine(result.FormData.GetType().Name);
}
}
public class NestedJason
{
public string FormName { get; set; }
public Object FormData { get; set; }
}
(I personally will be using the previous JsonNode option, that is more editable, but the object option skips that round trip serialization kludge.)

Serialize class object to JSON with a custom format

Running this program..
using System;
using System.Text.Json;
using System.Collections.Generic;
namespace XmlConsoleApp
{
class Program
{
static void Main(string[] args)
{
CampaignAccountMap campaignAccountMap = new CampaignAccountMap();
CampaignAccountMapItem campaignAccountMapItem = new CampaignAccountMapItem();
campaignAccountMapItem.CampaignId = #"dfdf-fdfdd-fdfd-dfdfd-dfdfd";
campaignAccountMapItem.AccountIds.Add(1245345);
campaignAccountMapItem.AccountIds.Add(1345675);
campaignAccountMap.Campaigns.Add(campaignAccountMapItem);
string jsonString = JsonSerializer.Serialize<CampaignAccountMap>(campaignAccountMap);
Console.Write(jsonString);
}
}
}
class CampaignAccountMap
{
public List<CampaignAccountMapItem> Campaigns { get; set; }
public CampaignAccountMap()
{
Campaigns = new List<CampaignAccountMapItem>();
}
}
class CampaignAccountMapItem
{
public string CampaignId { get; set; }
public List<int> AccountIds { get; set; }
public CampaignAccountMapItem()
{
AccountIds = new List<int>();
}
}
Outputs this JSON:
{
"Campaigns": [
{
"CampaignId": "dfdf-fdfdd-fdfd-dfdfd-dfdfd",
"AccountIds": [
1245345,
1345675
]
}
]
}
How can I customize the serialized output such that it produces this output instead?
{
"dfdf-fdfdd-fdfd-dfdfd-dfdfd": [
1245345,
1345675
]
}
Changing the name of the properties in from the class to the JSON seems doable using sterilizing annotations and such but I cant find any examples where those names are dynamic, ie I need the keys in the JSON output to be the dynamic values from the CampaignId property in the class.
I'm also open to doing this without using classes if I need to.
One way is to just use a Dictionary.
var dict = new Dictionary<string, List<int>>();
foreach (var item in campaignAccountMap.Campaigns)
{
dict[item.CampaignId] = item.AccountIds;
}
var jsonString = JsonSerializer.Serialize(dict);
Console.Write(jsonString);
The desired json format can be represented by Dictionary<string, List<int>>.
So, you could add a ToDictionary method to your class, something like this:
class CampaignAccountMapItem
{
public string CampaignId { get; set; }
public List<int> AccountIds { get; set; }
public CampaignAccountMapItem()
{
AccountIds = new List<int>();
}
public Dictionary<string, List<int>> ToDictionary()
{
return new Dictionary<string, List<int>> {{ CampaignId, AccountIds }};
}
}
And use it like:
string jsonString = JsonSerializer.Serialize(campaignAccountMapItem.ToDictionary());
Console.Write(jsonString);

C# Deserialization of JSON for use in a foreach loop

I have json that is posted from a HTTP req. I am trying to deserialize it for use in a for each loop. Unfortunately, its format is kicking my ass as its a list of objects (i believe).
so far i have the following:
dynamic jsonObj = JsonConvert.DeserializeObject(await req.ReadAsStringAsync());
foreach (var p in jsonObj.hireSchedules)
{
///do something
}
My json is as below:
{
"hireSchedules": [
{
"plant": "7246054",
"num" : "79",
"hire": "1137277"
},
{
"plant": "7246055",
"num" : "80",
"hire": "1137278"
}
]
}
I have the following classes:
public class HireSchedule
{
public string plant { get; set; }
public string num { get; set; }
public string hire { get; set; }
}
public class RootObject
{
public List<HireSchedule> hireSchedules { get; set; }
}
Any help would be appreciated. Thanks!
Since you have already defined the classes it's easy enough to deserialize it into them. Then you have a strongly typed class and the IDE should be able to help you out how to access the properties.
var json = File.ReadAllText("json1.json");
var root = JsonConvert.DeserializeObject<RootObject>(json);
foreach (var p in root.hireSchedules)
{
///do something
}
One of the way is to use Newtonsoft.json nuget which is really very powerful, so
var files = JObject.Parse(YourJSON);
var recList = files.SelectTokens("$..hireSchedules").ToList();
foreach (JObject obj in recList.Children())
{
foreach (JProperty prop in obj.Children())
{
var key = prop.Name.ToString();
var value = prop.Value.ToString();
//Do your stuffs here
}
}

is it possible to access properties by name, which is a variable?

Sorry if this is asked and answered, I searched but think I don't know the vocabulary to find the answer. Researched reflection but that doesn't seem to be the answer here? I'm a novice obviously. I'm trying/making minor contributions to a mod for the new Battletech game.
I've got this Dictionary and would like to use its keys to set properties as in the foreach below. I don't know if this is at compile or runtime, my guess is compile time...
I put *limb* in as pseudo-code for how I'm imagining it might work. The property mechDef.Head is an object of type LocationLoadoutDef with its property CurrentInternalStructure being float.
Hope that makes sense!
Much obliged for any assistance.
public class Settings {
public readonly Dictionary<string, bool> LimbRepair = new Dictionary<string, bool> {
{ "Head", false },
{ "LeftArm", false },
{ "RightArm", false },
{ "CenterTorso", false },
{ "LeftTorso", false },
{ "RightTorso", false },
{ "LeftLeg", false },
{ "RightLeg", false },
};
}
MechDef mechDef = new MechDef
(__instance.DataManager.MechDefs.Get(id), __instance.GenerateSimGameUID());
foreach (string limb in settings.LimbRepair.Keys) {
if (!settings.LimbRepair[limb]) {
mechDef.*limb*.CurrentInternalStructure = Math.Max
(1f, mechDef.*limb*.CurrentInternalStructure * (float)rng.NextDouble());
}
You can do it with Reflection, but....
This is quite easy to do with Reflection, and you'll probably get a couple answers on here that show you how, but since you are writing a game, I'm guessing you want the best performance possible, and Reflection isn't always going to give you that.
Below is a solution that requires no reflection but still allows you to use the loop structure you want. It just requires a little bit of setup when you create the object, then you can access your properties as if they were in a dictionary.
Solution: Use a dictionary of delegates to map the properties
First we need to write a utility class that represents a property. Since properties can be different types, this is a generic class with a type argument.
class PropertyWrapper<T>
{
private readonly Func<T> _getter;
private readonly Action<T> _setter;
public PropertyWrapper(Func<T> getter, Action<T> setter)
{
_getter = getter;
_setter = setter;
}
public T Value
{
get
{
return _getter();
}
set
{
_setter(value);
}
}
}
The idea behind this class is that you create it to represent any property you want, and call its methods to read and set the property. The class knows how to read and set the property because you tell it how, when you construct it, by passing it a short lambda expression that does the work.
This utility will allow you to put all the properties that represent limbs into a dictionary. Then you can look them up by string, just like your settings. So for example your MechDefinition might look like this:
class MechDef
{
public Limb Head { get; set; }
public Limb LeftArm { get; set; }
public Limb RightArm { get; set; }
public Limb LeftTorso { get; set; }
public Limb RightTorso { get; set; }
public Limb CenterTorso { get; set; }
public Limb RightLeg { get; set; }
public Limb LeftLeg { get; set; }
private readonly Dictionary<string, PropertyWrapper<Limb>> Properties;
public MechDef()
{
Properties = new Dictionary<string, PropertyWrapper<Limb>>
{
{"Head", new PropertyWrapper<Limb>( () => Head, v => Head = v ) },
{"LeftArm", new PropertyWrapper<Limb>( () => LeftArm, v => LeftArm = v ) },
{"RightArm", new PropertyWrapper<Limb>( () => RightArm, v => RightArm = v ) },
{"CenterTorso",new PropertyWrapper<Limb>( () => CenterTorso, v => CenterTorso = v )},
{"RightTorso", new PropertyWrapper<Limb>( () => RightTorso, v => RightTorso = v ) },
{"LeftTorso", new PropertyWrapper<Limb>( () => LeftTorso, v => LeftTorso = v ) },
{"RightLeg", new PropertyWrapper<Limb>( () => RightLeg, v => RightLeg = v ) },
{"LeftLeg", new PropertyWrapper<Limb>( () => LeftLeg, v => LeftLeg = v ) }
};
foreach (var property in Properties.Values) property.Value = new Limb();
}
public Limb this[string name]
{
get
{
return Properties[name].Value;
}
set
{
Properties[name].Value = value;
}
}
}
Yes, there is a bit of setup there, but it's all in one place, and it only executes once, when you instantiate the MechDef. Now you can access all of the limbs by string:
foreach (var pair in settings.LimbRepair)
{
if (pair.Value != false) continue;
var limb = mechDef[pair.Key];
limb.CurrentInternalStructure = Math.Max
(
1.0F,
limb.CurrentInternalStructure * (float)rng.NextDouble()
);
}
Link to DotNetFiddle example
You can create a DynamicObject to create your own dynamic Dictionary, See the explanation here
Assume that you want to provide alternative syntax for accessing
values in a dictionary, so that instead of writing
sampleDictionary["Text"] = "Sample text", you can write
sampleDictionary.Text = "Sample text".
This is the example from the same MSDN article above:
public class DynamicDictionary : DynamicObject
{
// The inner dictionary
Dictionary<string, object> dictionary = new Dictionary<string, object>();
public int Count
{
get { return dictionary.Count; }
}
// If you try to get a value of a property not defined
// in the class, this method is called.
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
// Converting the property name to lowercase so
// that property names become case-insensitive.
string name = binder.Name.ToLower();
// If the property name is found in a dictionary, set the result parameter
// to the property value and return true. Otherwise, return false.
return dictionary.TryGetValue(name, out result);
}
// If you try to set a value of a property that is not
// defined in the class, this method is called.
public override bool TrySetMember(SetMemberBinder binder, object value)
{
// Converting the property name to lowercase so that
// property names become case-insensitive.
dictionary[binder.Name.ToLower()] = value;
// You can always add a value to a dictionary, so this method always returns true.
return true;
}
}
And this is how you can use your DynamicDictionary:
dynamic person = new DynamicDictionary();
// Adding new dynamic properties. The TrySetMember method is called.
person.FirstName = "Ellen";
person.LastName = "Adams";
Reflection is one way to get at it. https://stackoverflow.com/a/1954663/83250 actually answers this perfectly. I would however restructure your data so the mechDef object is another dictionary but if you must keep it like your question asks, this will work:
void Main()
{
Dictionary<string, bool> limbRepair = new Dictionary<string, bool>
{
{ "Head", false },
{ "LeftArm", false },
{ "RightArm", false },
// Etc.
};
MechDefinition mechDef = new MechDefinition();
List<Limb> limbs = new List<Limb>();
foreach (KeyValuePair<string, bool> limbsToRepair in limbRepair.Where(x => !x.Value))
{
Limb limb = mechDef.GetPropValue<Limb>(limbsToRepair.Key);
limb.CurrentInternalStructure = 9001;
}
}
public class MechDefinition
{
public MechDefinition()
{
Head = new Limb
{
Id = Guid.NewGuid(),
DateAdded = DateTime.Parse("2018-01-01"),
Name = "Main Head",
CurrentInternalStructure = 8675309
};
}
public Guid Id { get; set; }
public string Name { get; set; }
public int CurrentInternalStructure { get; set; }
public Limb Head { get; set; } = new Limb();
public Limb LeftArm { get; set; } = new Limb();
public Limb RightArm { get; set; } = new Limb();
// etc...
}
public class Limb
{
public Guid Id { get; set; }
public string Name { get; set; }
public DateTime DateAdded { get; set; }
public int CurrentInternalStructure { get; set; }
public bool IsDisabled { get; set; }
}
public static class ReflectionHelpers
{
public static object GetPropValue(this object obj, string name)
{
foreach (string part in name.Split('.'))
{
if (obj == null) { return null; }
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(part);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
return obj;
}
public static T GetPropValue<T>(this object obj, string name)
{
object retval = GetPropValue(obj, name);
if (retval == null) { return default(T); }
// throws InvalidCastException if types are incompatible
return (T)retval;
}
}
Be aware that reflection is a very costly operation. If you are dealing with large sets of data, it will be very inefficient. Take a look at https://stackoverflow.com/a/7478557/83250 for a performance overview.
Also code-wise, I prefer to stay away from dynamic and reflection altogether. Reflection has its perks when you need to access a property attribute and dynamic is great if you don't have a strongly typed object. With that said, C# is a strongly typed language and should be treated as such whenever possible. By restructuring your mechDef as a Dictionary<string, Limb> object or something similar you will have a more efficient application.
If I understand correctly, You have something like this:
class LocationLoadoutDef
{
public LocationLoadoutDef()
{
Head = new Prop();
LeftArm = new Prop();
RightArm = new Prop();
CenterTorso = new Prop();
LeftTorso = new Prop();
RightTorso = new Prop();
LeftLeg = new Prop();
RightLeg = new Prop();
}
public Prop Head { get; set; }
public Prop LeftArm { get; set; }
public Prop RightArm { get; set; }
public Prop CenterTorso { get; set; }
public Prop LeftTorso { get; set; }
public Prop RightTorso { get; set; }
public Prop LeftLeg { get; set; }
public Prop RightLeg { get; set; }
...
}
class Prop
{
public float CurrentInternalStructure { get; set; }
...
}
So you can use reflection getting the type of the object and the property.
This is an example based on your pseudocode:
// your instance of LocationLoadoutDef
var mechDef = new LocationLoadoutDef();
//For reflection you need obtain the type
Type mechType = mechDef.GetType();
// loop your Dictionary
foreach (string limb in LimbRepair.Keys)
{
// If the property is false in the dictionary and the type has a property with that name
if (!LimbRepair[limb] && mechType.GetProperties().Any(p => p.Name == limb))
{
// Obtain the instance of the property
var property = mechType.GetProperty(limb).GetValue(mechDef) ;
// Get the property type
Type propertyType = property.GetType();
// If the property has a property CurrentInternalStructure
if (propertyType.GetProperties().Any(p => p.Name == "CurrentInternalStructure"))
{
// Obtain the current value for CurrentInternalStructure
var currentValue = propertyType.GetProperty("CurrentInternalStructure").GetValue(property);
// calculate the new value (I don't know what is rng)
var newValue = 1f ; //Math.Max(1f, (float)currentValue * (float)rng.NextDouble());
// set de value in the property
propertyType.GetProperty("CurrentInternalStructure").SetValue(property, newValue);
}
}
}
You can always create classic and working if .. else or switch.
Or create dictionary with function to update correct property
public class Repair
{
public bool Active { get; set; }
public Action<MechDef> Update { get; set; }
}
public class Settings
{
public readonly Dictionary<string, Repair> LimbRepair =
new Dictionary<string, bool> {
{
"Head",
new Repair { Active = false, mechDef => mechDef.Head.CurrentInternalStructure = yourFunctionForHead }
},
{
"LeftArm",
new Repair { Active = false, mechDef => mechDef.LeftArm.CurrentInternalStructure = yourFunctionForLeftArm }
},
// ... and so on
};
}
Then in the loop you will call correct update action, become much cleaner to use settings class with benefits of strong types and compiler help which prevent dynamic runtime errors
var updates = settings.LimbRepair.Where(pair => pair.Value.Active == false)
.Select(pair => pair.Value);
foreach (var repair in updates)
{
repair.Update();
}

How do you serialize non-standard JSON with JSON.net? [duplicate]

I have to read a JSON stream (which I have no control over), which is in the form:
{"files":
{
"/some_file_path.ext": {"size":"1000", "data":"xxx", "data2":"yyy"},
"/other_file_path.ext": {"size":"2000", "data":"xxx", "data2":"yyy"},
"/another_file_path.ext": {"size":"3000", "data":"xxx", "data2":"yyy"},
}
}
So, I have an object named files, which has a number of properties, which have 1) different names every time, 2) different number of them every time, and 3) names with characters which can't be used in C# properties.
How do I deserialize this?
I'm putting this into a Portable Library, so I can't use the JavaScriptSerializer, in System.Web.Script.Serialization, and I'm not sure about JSON.NET. I was hoping to use the standard DataContractJsonSerializer.
UPDATE: I've changed the sample data to be closer to the actual data, and corrected the JSON syntax in the area the wasn't important. (Still simplified quite a bit, but the other parts are fairly standard)
You can model your "files" object as a Dictionary keyed by the JSON property name:
public class RootObject
{
public Dictionary<string, PathData> files { get; set; }
}
public class PathData
{
public int size { get; set; }
public string data { get; set; }
public string data2 { get; set; }
}
Then, only if you are using .Net 4.5 or later, you can deserialize using DataContractJsonSerializer, but you must first set DataContractJsonSerializerSettings.UseSimpleDictionaryFormat = true:
var settings = new DataContractJsonSerializerSettings { UseSimpleDictionaryFormat = true };
var root = DataContractJsonSerializerHelper.GetObject<RootObject>(jsonString, settings);
With the helper method:
public static class DataContractJsonSerializerHelper
{
public static T GetObject<T>(string json, DataContractJsonSerializer serializer = null)
{
using (var stream = GenerateStreamFromString(json))
{
var obj = (serializer ?? new DataContractJsonSerializer(typeof(T))).ReadObject(stream);
return (T)obj;
}
}
public static T GetObject<T>(string json, DataContractJsonSerializerSettings settings)
{
return GetObject<T>(json, new DataContractJsonSerializer(typeof(T), settings));
}
private static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
}
}
Alternatively, you can install Json.NET and do:
var root = JsonConvert.DeserializeObject<RootObject>(jsonString);
Json.NET automatically serializes dictionaries to JSON objects without needing to change settings.
We need to first convert this Invalid JSON to a Valid JSON. So a Valid JSON should look like this
{
"files":
{
"FilePath" : "C:\\some\\file\\path",
"FileData" : {
"size": 1000,
"data": "xxx",
"data2": "yyy"
},
"FilePath" :"C:\\other\\file\\path",
"FileData" : {
"size": 2000,
"data": "xxx",
"data2": "yyy"
},
"FilePath" :"C:\\another\\file\\path",
"FileData" : {
"size": 3000,
"data": "xxx",
"data2": "yyy"
}
}
}
To make it a valid JSON we might use some string functions to make it looks like above. Such as
MyJSON = MyJSON.Replace("\\", "\\\\");
MyJSON = MyJSON.Replace("files", "\"files\"");
MyJSON = MyJSON.Replace("data:", "\"data:\"");
MyJSON = MyJSON.Replace("data2", "\"data2\"");
MyJSON = MyJSON.Replace(": {size", ",\"FileData\" : {\"size\"");
MyJSON = MyJSON.Replace("C:", "\"FilePath\" :\"C:");
Than we can create a class like below to read the
public class FileData
{
public int size { get; set; }
public string data { get; set; }
public string data2 { get; set; }
}
public class Files
{
public string FilePath { get; set; }
public FileData FileData { get; set; }
}
public class RootObject
{
public Files files { get; set; }
}
Assuming you have a valid JSON you could use JavaScriptSerializer to return a list of objects
string json = "{}"
var serializer = new JavaScriptSerializer();
var deserializedValues = (Dictionary<string, object>)serializer.Deserialize(json, typeof(object));
Alternatively you could specify Dictionary<string, List<string>> as the type argument
strign json = "{}";
JavaScriptSerializer serializer = new JavaScriptSerializer();
var deserializedValues = serializer.Deserialize<Dictionary<string, List<string>>>(json);
foreach (KeyValuePair<string, List<string>> kvp in deserializedValues)
{
Console.WriteLine(kvp.Key + ": " + string.Join(",", kvp.Value));
}

Categories