Deserialize json string array to string array - c#

Lets assume I have the following JSON Object:
{
"Key": "\"QTuY+0m31w2QiZGl4h+W8w==\"",
"Value":
[
"addgroup",
"viewgroup",
"editgroup"
]
}
How can I deserialize the Value part in a C# string[]?
The problem is, string[] is not the only type I have in the Value part, it can be everything, so I need to use dynamic.
I am using JSON.net and when I use the JsonConvert.DeserializeObject method I get a runtime binder exception.
This is the method I use to deserialize:
public async Task<Tuple<string, dynamic>> ReadCachingEntryAsync(string uri) {
var data = tools.ReadEntry(Path.Combine(cacheFolder, uri.Replace("/", "")));
var res = new Tuple<string, dynamic>(string.Empty, null);
if (data != null) {
var dat = JsonConvert.DeserializeObject<KeyValuePair<string, dynamic>>(UTF8Encoding.UTF8.GetString(data));
res = new Tuple<string, dynamic>(dat.Key, dat.Value);
}
return res;
}
The tools.ReadEntry(data) returns a byte[] containing the data, from the binary formatted file.
Here is the class KeyValuePair<K, V>
[Serializable]
internal struct KeyValuePair<K, V> {
public K Key { get; set; }
public V Value { get; set; }
}

You can check if it's a JArray and implement special handling. E.g.
byte[] data = Encoding.UTF8.GetBytes(#"{""Key"": ""Something"", ""Value"": [""test"", ""test 2"", ""test 3""]}");
var dat = JsonConvert.DeserializeObject<KeyValuePair<string, dynamic>>(UTF8Encoding.UTF8.GetString(data));
var value = dat.Value;
if (value is JArray)
{
var arrayType = value[0].Value.GetType().MakeArrayType();
value = value.ToObject(arrayType);
}
var res = new Tuple<string, dynamic>(dat.Key, value);

Just call DeserializeObject<T> replacing T with the type you intend to deserialize the input string into and json.NET will take care of the rest.
string[] json = JsonConvert.DeserializeObject<string[]>(inputString);
EDIT:
Ok, so assuming all of your json is in the form of the example posted in EDIT 3 then waht you really want is;
public class KVPair
{
public string Key { get; set; }
public string[] Value { get; set; }
}
KVPair pair = JsonConvert.DeserializeObject<KVPair>(UTF8Encoding.UTF8.GetString(data));
Now this is fairly static but I'm not sure you actually need dynamic. If you do then you'll want the Value property to be of type object or dynamic. However, if you go that route then you will unfortunately have to deal with this unknown type. I'm really not knowledgeable on the dynamic type so I can't comment on how to deal with it later on but if say for example, the array could contain, ints, floats or strings and you made Value of type object you would have inspect the array later on, determine the underlying type and cast each of the items to that type before you could do anything useful with them. Hope that helps. If you're lucky you'll just be able to use the code I posted above as it's far simpler and is actually type safe.

Related

Json array to C# class

I’ve got a very simple scenario.
I have an api response that simply returns an array of strings.
[‘test’,’test2’,’test3’]
I need to deserialise into an object to integrate with some current code.
I’ve tried using a straight class with a single property of type List but no dice.
How to deserialise into single object?
If you are using Visual Studio, you can try to use the Paste special - Paste JSON as classes under the Edit menu. Otherwise you can use this simple tool https://json2csharp.com/.
For deserialize the json string, you can use this two extension method:
using System.Runtime.Serialization.Json;
public static T DeserializeFromJsonString<T>(this string data)
{
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(data)))
return stream.DeserializeFromJsonStream<T>();
}
public static T DeserializeFromJsonStream<T>(this Stream stream)
{
T result = (T)new DataContractJsonSerializer(typeof(T)).ReadObject(stream);
return result;
}
if you need deserialise the api outPut into single object:
class _object
{
public List<string> value { get; set; }
public _object(List<string> val)=>
value = val;
}
string[] apiOutput = { "test", "test2", "test3" };
_object myobject = new _object(apiOutput.ToList());
If you want to convert the array into a list of objects:
class _object
{
public string value { get; set; }
public _object(string val)=>
value = val;
}
string[] apiOutput = {"test", "test2", "test3"};
List<_object> listObjest = apiOutput.Select(x => new _object(x)).ToList();
listObjest.ForEach(x=>Console.WriteLine(x.value));

How to obtain a list of dynamic object keys/values from NewtonSoft Deserialised into Dynamic var

I have a C# class that receives a JSON string, and deserialises it into a dynamic.
json = #"{
"Id": "97dc4a96-43cf-48bd-9358-8f33e910594e",
"RepId": 90037,
"Something": true,
"SomethingElse": "abcdefg",
"Thing_1_of_MaybeDozens": 55
}";
dynamic jsonData = JsonConvert.DeserializeObject(json);
I can't deserialse into a class because while each JSON string will always have two known data elements (Id, and RepId), the rest of the string may have many elements that I do not know ahead of time their names, or how many of them there are.
I can always ask for jsonData.Id, or jsonData.RepId, but I do not know how many other elements there may be, nor how to refer to them.
I need something similar to JavaScript's Object.Keys(myObject).
Anyone knows how to do similar in C# with a Newtonsoft Deserialised JSON string?
You can use Reflection:
public Dictionary<string, object> DynamicToDictionary(dynamic obj)
{
var dict = new Dictionary<string, object>();
foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(obj))
{
object obj2 = pd.GetValue(obj);
dict.Add(pd.Name, obj2);
}
return dict;
}
Now you may use the dictionary's TryGetValue(), and ContainsKey().
try to use Newtonsoft.Json extensions
var data = JsonConvert.DeserializeObject<Data>(json);
list of keys
List<string> additionalKeys=data.AdditionalData.Select(ad => ad.Key).ToList();
output
["Something","SomethingElse","Thing_1_of_MaybeDozens"]
how to use
var id = data.Id; //97dc4a96-43cf-48bd-9358-8f33e910594e
var somethingElse = data.AdditionalData["SomethingElse"]; // abcdefg
class
public class Data
{
// normal deserialization
public string Id { get; set; }
public long RepId { get; set; }
//additional data
[JsonExtensionData]
public Dictionary<string, object> AdditionalData {get;set;}
}

Deserialize string by class name

Let's say I have a Value that is deserialized from a class.
public class MyValue
{
public string MyPropertyA { get; set; }
public string MyPropertyB { get; set; }
public string DeserializationClass { get; } = typeof(MyValue).Name;
}
I serialize this using JsonConvert class. MyValue class has a property DeserializationClass that should be used as info from which class the string was serialized from. In other words, when I deserialize the string into an object, this property serves as info which class should be used to deserialize the string. However, I am kinda stuck here as I am not sure how to get back the class from the string. Can anybody help me here?
public class Program
{
void Main()
{
var serialized = Serialize();
var obj = Deserialize(serialized);
}
string Serialize()
{
var objValue = new MyValue { MyPropertyA="Something", MyPropertyB="SomethingElse" };
return JsonConvert.SerializeObject<MyClass>(value);
}
object Deserialize(string serialized)
{
//How to deserialize based on 'DeserializationClass' property in serialized string?
return = JsonConvert.Deserialize<???>(serialized);
}
}
EDIT: Modified example to make it more clear what I need as I don't have access to objValue when I need to deserialize the string.
probably you might need to use JsonSerializerSettings.
What you might need to do is
JsonSerializerSettings setting = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
};
and then while serializing use this setting.
var serialized = JsonConvert.SerializeObject(objValue,setting);
this will give you Json like this
{"$type":"WPFDatagrid.MyValue, WPFDatagrid","MyPropertyA":"Something","MyPropertyB":"SomethingElse","DeserializationClass":"MyValue"}
from this you can find the name of the class used it to actually get your type.
Hope this helps !!
There is an overload
If your Type is in form of a Namespace, you can obtain the type from a string representation:
Type objValueType = Type.GetType("Namespace.MyValue, MyAssembly");
object deserialized = JsonConvert.Deserialize(objValueType, serialized);

Is there any way to create in foreach loop?

Here is my code:
var json = File.ReadAllText(#"C:\sira.json");
dynamic x = JsonConvert.DeserializeObject<dynamic>(json);
Arac.adli_tip = x.adli_tip;
Arac.aile_hukuku = x.aile_hukuku;
Arac.avrupa_birligi_hukuku = x.avrupa_birligi_hukuku;
Arac.bankacilik_hukuku = x.bankacilik_hukuku;
Arac.bilisim_hukuku = x.bilisim_hukuku;
Arac.borclar_hukuku = x.borclar_hukuku;
Arac.cevre_hukuku = x.cevre_hukuku;
Arac.deniz_ticareti_hukuku = x.deniz_ticareti_hukuku;
Arac.devletler_ozel_hukuku = x.devletler_ozel_hukuku;
Arac.esya_hukuk = x.esya_hukuk;
.
.
.
sira.json is a configuration file about my winforms app.
Here is content of sira.json file:
{
"adli_tip": 15,
"aile_hukuku": 43,
"avrupa_birligi_hukuku": 22,
"bankacilik_hukuku": 10,
.
.
.
"vergi_hukuku": 3
}
I want to get some values from file and set static variables. But these config variables nearly 60.
Is there any way to set static variables programmatically, for example with forecach or while?
EDIT: #subi_speedrunner comment and #T.J.Crowder reply, I searched about Reflection and I coded like this:
But it gives an error. I did not understand why?
Assuming Arac property names match exactly to json property names and Arac properties are public static properties, the following code will work:
using Newtonsoft.Json.Linq;
using System;
namespace ConsoleApplication1
{
public static class Arac
{
public static int adli_tip { get; set; }
public static int aile_hukuku { get; set; }
public static int avrupa_birligi_hukuku { get; set; }
public static int bankacilik_hukuku { get; set; }
public static string string_value {get; set;}
public static DateTime date_value { get; set; }
}
class Program
{
static void Main(string[] args)
{
var json = #"
{
""adli_tip"": 15,
""aile_hukuku"": 43,
""avrupa_birligi_hukuku"": 22,
""bankacilik_hukuku"": 10,
""string_value"": ""some value"",
""date_value"": ""2016-01-24 11:18:00""
}";
JObject arac = JObject.Parse(json);
foreach (var prop in typeof(Arac).GetProperties(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public))
{
var token = arac.GetValue(prop.Name);
if (token != null)
{
object value = token.ToObject(prop.PropertyType);
prop.SetValue(null, value, null);
}
}
Console.WriteLine("adli_tip {0}", Arac.adli_tip);
Console.WriteLine("aile_hukuku {0}", Arac.aile_hukuku);
Console.WriteLine("avrupa_birligi_hukuku {0}", Arac.avrupa_birligi_hukuku);
Console.WriteLine("bankacilik_hukuku {0}", Arac.bankacilik_hukuku);
Console.WriteLine("string_value {0}", Arac.string_value);
Console.WriteLine("date_value {0}", Arac.date_value);
}
}
}
Note that I use JObject directly instead of JsonConvert.DeserializeObject, this is because JsonConvert.DeserializeObject<dynamic> actually returns a JObject, and I prefer all features of JObject than working with a generic dynamic object.
The code works with integer properties as well as other type of properties as you can see on the sample code.
The following is the relevant code:
JObject arac = JObject.Parse(json);
foreach (var prop in typeof(Arac).GetProperties(BindingFlags.Static | BindingFlags.Public))
{
var token = arac.GetValue(prop.Name);
if (token != null)
{
object value = token.ToObject(prop.PropertyType);
prop.SetValue(null, value, null);
}
}
Yes, you can use reflection, defined in the System.Reflection namespace. Rough sketch:
Get the Type objects for Arac and x
Have an array of the field names you want to process, or use Type object for Arac's GetProperties and/or GetFields methods to get an array of all of its properties/fields (you can specify various features, like whether you only want public ones, etc.)
Loop through the array or the list and for each field:
If you don't already have a FieldInfo/PropertyInfo object from Arac's Type object, use Type#GetField or Type#GetProperty (or one of their relatives) to get it
Get the FieldInfo/PropertyInfo for x's Type object for the same field/property
Use the GetValue method(s) of the FieldInfo/PropertyInfo you got from x's type object to read the value, and the SetValue method(s) of the other FieldInfo/PropertyInfo object to write the value to Arac
Not necessarily saying it's a good idea, since as soon as you put those field names into strings, you make it harder to refactor them with tools, etc., but if the question is "Can I do this?" the answer is "Yes" (and sometimes it's a reasonable choice, there are just trade-offs).

Newtonsoft.Json: error on deserialize objects with generic fields

I have a question: Does Json.NET correctly work with generics? I have the next code:
[TestClass]
public class TestClass1_Test
{
[TestMethod]
public void ToJson()
{
var mot = new TestClass1(1, "title");
var result = mot.ToJson();
Assert.IsNotNull(result);
var pobject = TestClass1.FromJson(result);
Assert.AreEqual(pobject.Id, mot.Id);
}
}
public class TestClass1
{
public TestClass1(int id, string name)
{
Id = new Field<int>(id);
Name = new Field<string>(name);
}
public Field<int> Id { get; set; }
public Field<string> Name { get; set; }
public string ToJson()
{
var jobject = JObject.FromObject(this);
return jobject.ToString();
}
public static TestClass1 FromJson(string json)
{
var obj = JObject.Parse(json).ToObject<TestClass1>();
return obj;
}
}
public class Field<T>
{
public Field(T val)
{
Value = default(T);
}
public T Value { get; set; }
}
But when I call var obj = JObject.Parse(json).ToObject<TestClass1>() I get next error:
Newtonsoft.Json.JsonReaderException: Error reading integer. Unexpected
token: StartObject. Path 'Id', line 2, position 10.
Where is my mistake? Or Json.NET does not work with generics?
Json.NET does indeed work with generics - I was able to serialize and deserialize one of your Field<int> objects just fine.
The error message I get with the above code (using Json.NET 4.5 r10) is:
Error reading integer. Unexpected token: StartObject. Path 'Id', line 2, position 10
where the stack trace implied it was trying to deserialize an integer when it ran into a {, which was the beginning of the Id object. I think this could well be a bug.
Yet this seems to work as expected when using Json.NET 3.5 r8. I did have to swap JsonConvert.DeserializeObject<TestClass1>(json) for JObject.Parse(json).ToObject<TestClass1>() as the latter isn't in this version.
The answer therefore is to try a different version of Json.NET.
There is also a bug in the Field constructor.
Value = default(T);
should be:
Value = val;
For reference; this error can also come about if you are deserializing an object that contains a nested JSON object as a string.
If you forget to stringify it, the parser throws up this error.

Categories

Resources