How to pass a class as a parameter - c#

I have following method, which is read JSON from the directory and de-serialize the JSON into C# class object.
public static JObject readJson(string fileName)
{
string JSON = "";
List<string> keyList = new List<string>();
using (StreamReader r = new StreamReader(fileName))
{
JSON = r.ReadToEnd();
}
JObject parsed = JObject.Parse(JSON);
var name = parsed["2"];
Numbers deserializedClass = JsonConvert.DeserializeObject<Numbers>(name.ToString());
return parsed;
}
Here you can see, I'm used class called Numbers. I'm passing separate JSON file's name to the above method, based on that I also need to pass Class to convert JSON into C# object. How can I pass class to the above method as a generic? then I think I can modify this line,
var deserializedClass = JsonConvert.DeserializeObject<AnyClass>(name.ToString());
is it possible to do?

try this:
public static JObject readJson<T>(string fileName)
{
string JSON = "";
List<string> keyList = new List<string>();
using (StreamReader r = new StreamReader(fileName))
{
JSON = r.ReadToEnd();
}
JObject parsed = JObject.Parse(JSON);
var name = parsed["2"];
Numbers deserializedClass = JsonConvert.DeserializeObject<T>(name.ToString());
return parsed;
}
https://learn.microsoft.com/en-us/dotnet/standard/generics/
https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/types/generics

This method uses Generics and will take the Type you specify and return the object of that type.
public static T readJson<T>(string fileName)
{
var JSON = string.Empty;
using (var r = new StreamReader(fileName))
{
JSON = r.ReadToEnd();
}
var parsed = JObject.Parse(JSON);
var name = parsed["2"];
var deserializedClass = JsonConvert.DeserializeObject<T>(name.ToString());
return deserializedClass;
}
Usage:
var resultObject = readJson<Number>(fileName);
https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/types/generics

Related

How to inline JSON structure with System.Text.Json

I am looking for the equivalent of Golang's json: "inline" tag with C#'s System.Text.Json.
For example, I have the following class structure in C#:
class Outer{
public string Hello;
public Inner TheInner;
}
class Inner{
public string Earth;
public string Moon;
}
And I want the serialized and deserialized JSON text to be
{
"Hello" : "example_value_01",
"Earth" : "example_value_02",
"Moon" : "example_value_03"
}
In Golang, I can achieve this with the following structure definition
type Outer struct{
Hello string
TheInner Inner `json: "inline"`
}
type Inner struct{
Earth string
Moon string
}
However, I cannot find a decent way to do this in C#'s System.Text.Json.
To reach it in c# , you don't need any custom classes at all,you can use a dictionary
var dict = new Dictionary<string, string> {
{"Hello","example1"},
{"World","example2"}
};
var json= System.Text.Json.JsonSerializer.Serialize(dict,new JsonSerializerOptions { WriteIndented = true});
result
{
"Hello": "example1",
"World": "example2"
}
but if you want it a hard way it is much easier to make it using Newtonsoft.Json since Text.Json needs a custom serializer for almost everything
using Newtonsoft.Json;
var json = SerializeOuterObj(obj, "TheInner");
obj = DeserializeOuterObj(json);
public string SerializeOuterObj(object outerObj, string innerObjectPropertyName)
{
var jsonParsed = JObject.FromObject(outerObj);
var prop = jsonParsed.Properties().Where(i => i.Name == innerObjectPropertyName).First();
prop.Remove();
foreach (var p in ((JObject)prop.Value).Properties())
jsonParsed.Add(p.Name, p.Value);
return jsonParsed.ToString();
}
public Outer DeserializeOuterObj(string json)
{
var jsonParsed = JObject.Parse(json);
var outer = jsonParsed.ToObject<Outer>();
outer.TheInner = jsonParsed.ToObject<Inner>();
return outer;
}
This solution uses reflexion, so is independant of number of string items in the class Inner and independant too of name of Inner Class, just you have to respect if its property or field:
public class Outer
{
public string? Hello;
public Inner? TheInner { get; set; }
}
public class Inner
{
public string? World1;
public string? World2;
public string? World3;
}
the program using the nested class:
var json= "{\"Hello\": \"hello\",\"World1\":\"world1\", \"World2\": \"world2\", \"World3\": \"world3\"}";
var ou = deserialize(json);
json = serialize(ou);
the methods serialize and deserialize:
public Outer deserialize(string json)
{
var fieldhello = typeof(Outer).GetFields().First();
var propinner = typeof(Outer).GetProperties().First();
var subfieldsinner = typeof(Inner).GetFields().ToArray();
var document = JsonDocument.Parse(json);
JsonElement root = document.RootElement;
var outer = new Outer();
var inner = new Inner();
var innerstArr = subfieldsinner.Select(f => (field: f, value: root.TryGetProperty(f.Name, out var item) ? item.GetString() : null));
foreach(var p in innerstArr)
p.field.SetValue(inner, p.value);
string? hellost = root.TryGetProperty(fieldhello.Name, out var item) ? item.GetString() : null;
fieldhello.SetValue(outer, hellost);
propinner.SetValue(outer, inner);
return outer;
}
public string serialize(Outer outer)
{
var fieldhello = outer.GetType().GetFields().First();
var propinner = outer.GetType().GetProperties().First();
var inn = (Inner) propinner.GetValue(outer, null);
var subfieldsinner = inn.GetType().GetFields().ToArray();
using var ms = new MemoryStream();
using var writer = new Utf8JsonWriter(ms);
writer.WriteStartObject();
writer.WriteString(fieldhello.Name, (string?)fieldhello.GetValue(outer));
foreach(var f in subfieldsinner)
writer.WriteString(f.Name, (string?)f.GetValue(inn));
writer.WriteEndObject();
writer.Flush();
string json = Encoding.UTF8.GetString(ms.ToArray());
return json;
}

How can deserialize using Newtonsoft.Json?

How to read it using Newtonsoft.Json?
{
"192.168.0.12":
{
"Name":"12",
"Mode":"STOP"
},
"192.168.0.13":
{
"Name":"13",
"Mode":"STOP"
}
}
I am using this data class as below:
class Device{
public string Name;
public string Mode;
}
Dictionary<string, Device> devices;
So, I tried this code to deserialize. But, I can't read value from JToken as dictionary.
JObject JDevices = JObject.Parse(Encoding.ASCII.GetString(buffer));
foreach (JProperty property in JDevices.Properties())
{
string name = property.Name;
JToken value = property.Value;
// to read Device.Name and Device.Mode
}
You can use dynamic object var result = JsonConvert.DeserializeObject<dynamic>(json);
Code to convert to Dictionary:
Dictionary<string, Device> devices = new Dictionary<string, Device>();
string json = "{\"192.168.0.12\": {\"Name\":\"12\",\"Mode\":\"STOP\"},\"192.168.0.13\": {\"Name\":\"13\",\"Mode\":\"STOP\"}}";
var result = JsonConvert.DeserializeObject<dynamic>(json);
foreach (var item in result)
{
var name = item.Name;
evices.Add(item.Name.ToString(), new Device {Name = item.Value.Name.ToString(), Mode = item.Value.Mode.ToString()});
}
Try this, no need to use dynamic.
var json = "{
"192.168.0.12":
{
"Name":"12",
"Mode":"STOP"
},
"192.168.0.13":
{
"Name":"13",
"Mode":"STOP"
}
}";
var result = JsonConvert.DeserializeObject<Dictionary<string, Device>>(json);
foreach (var device in result.Values)
{
var name = device.Name;
var mode = device.Mode;
}

How can i make a flat object by removing keys in C#?

I am really not sure if this could be achievable, How can i remove some nested keys in an Object and make the object very flat. I have a dynamic object as follows,
EventData": { "ChangeSet": { "Change": {
"changes": [
] } } }
and i want to change the above to
EventData": { [] }
is this can be achieved in C#?
Use the NewtonSoft.JSon package.. Following code does the trick. I made it a string array because I do not know what you need but you can change this to your liking.
const string complex = "{\"EventData\": { \"ChangeSet\": { \"Change\": { \"changes\" : [ ]}}}}";
Call to method:
string simple = returnSimpleObject(complex);
public class SerializeData
{
public string[] EventData { get; set; }
}
private static string returnSimpleObject(string Json)
{
JObject jobject = JObject.Parse(Json);
JToken tEventData = jobject.SelectToken("EventData");
SerializeData myEvent = tEventData.ToObject<SerializeData>();
JToken tchanges = jobject.SelectToken("EventData.ChangeSet.Change.changes");
myEvent.EventData = tchanges.ToObject<string[]>();
JsonSerializer serializer = new JsonSerializer();
StringWriter strWrite = new StringWriter();
JsonWriter myWriter = new JsonTextWriter(strWrite);
serializer.Serialize(myWriter, myEvent);
return strWrite.ToString();
}

UWP Json to C# conversion

I want to serialize some json data I get from the web to classes and use the data, so I went to http://json2csharp.com/ and turned the json as below
json: [{"line_descr":"\u03a0\u0395\u0399\u03a1\u0391\u0399\u0391\u03a3 -
\u0392\u039f\u03a5\u039b\u0391","line_descr_eng":"PEIRAIAS - VOYLA"}]
To this class:
public class RootObject
{
public string line_descr { get; set; }
public string line_descr_eng { get; set; }
}
This is my code:
class LineName
{
public async static Task<RootObject> GetLineName(int linecode)
{
var http = new HttpClient();
var response = await http.GetAsync("http://telematics.oasa.gr/api/?act=getLineName&p1=962");
var result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject)serializer.ReadObject(ms);
return data;
}
}
[DataContract]
public class RootObject
{
[DataMember]
public string line_descr { get; set; }
[DataMember]
public string line_descr_eng { get; set; }
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
RootObject myLine = await LineName.GetLineName(92);
ResultTextBlock.Text = myLine.line_descr_eng;
}
So when I try to get the data and display it in my textblock I get the error: line_descr_eng is null.
Can someone point where the fault is ? since the line_descr_eng should be
PEIRAIAS - VOYLA but mine is null and after a lot of searching I cant find where the fault is.
Your json is an array, not an object, and you should deserialize it into an array.
public async static Task<RootObject[]> GetLineName(int linecode)
{
var http = new HttpClient();
var response = await http.GetAsync("http://telematics.oasa.gr/api/?act=getLineName&p1=962");
var result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject[]));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject[])serializer.ReadObject(ms);
return data;
}
//...
var myLines = await LineName.GetLineName(92);
var myLine = myLines.FirstOrDefault();
Also you don't need a memory stream, you can read stream from the http response
var result = await response.Content.ReadAsStreamAsync();
You simple can use the JavaScriptSerializer class instead of DataContractJsonSerializer like this:
Replace:
var serializer = new DataContractJsonSerializer(typeof(RootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject)serializer.ReadObject(ms);
with this:
var ser = new JavaScriptSerializer();
var test = ser.Deserialize<List<RootObject>>(json);
If you cannot find JavaScriptSerializer, then you have to do the simple following steps:
Right click References and do Add Reference, then from Assemblies->Framework select System.Web.Extensions.
Now you should be able to add the following to your class file:
using System.Web.Script.Serialization;
Cited from: https://stackoverflow.com/a/15391388/5056173

Deserializing a JSON file with c#

My problem is
i have this JSON file:
and i have to save it in a list but when i try to print the first element of the list I get a System.ArgumentOutOfRangeException, as if my list is empty. this is my code:
JavaScriptSerializer ser = new JavaScriptSerializer();
Causali o = new Causali();
List<CausaliList> lista = new List<CausaliList>();
WebRequest causali = (HttpWebRequest)WebRequest.Create("http://trackrest.cgestmobile.it/causali");
WebResponse risposta = (HttpWebResponse)CreateCausaliRequest(causali).GetResponse();
Stream data = risposta.GetResponseStream();
StreamReader Leggi = new StreamReader(data);
string output = Leggi.ReadToEnd();
lista = ser.Deserialize<List<CausaliList>>(output);
lst2.Items.Add(lista[0]);
and these are my two class for the saves:
class Causali
{
public int id;
public string causaliname;
public string identificationcode;
public string expired;
}
and
class CausaliList
{
public Causali causali;
}
can you help me solve it?
please try this as your root object:
public class CausaliList
{
public List<Causali> causali { get; set; }
}
then deserilize your object like this:
lista = ser.Deserialize<CausaliList>(output);
finally you can access to list like this:
lst2.Items.Add(lista.causali[0]);
Note: i strongly recommend to use json.NET.
To deserialize the code in c#:
Lets assume you have data in var getContent then you may use this:
dynamic getDesearilize = JsonConvert.DeserializeObject(getContent);

Categories