I'm trying to capture the names and values of all nodes coming from a random Json file that I don't know its structure (uploaded by the user).
I can loop through a json string and get the info I need but how do I start from a file? If I want to deserialize it I believe I need a class to hold that data (and I don't know the file structure).
Here's how I loop through elements from a json string:
string json = #"{
'CPU': 'Intel',
'PSU': '500W',
'Drives': [
'DVD read/writer'
/*(broken)*/,
'500 gigabyte hard drive',
'200 gigabype hard drive'
]
}";
JsonTextReader reader = new JsonTextReader(new StringReader(json));
while (reader.Read())
{
if (reader.Value != null)
{
Console.WriteLine("Token: {0}, Value: {1}", reader.TokenType, reader.Value);
}
else
{
Console.WriteLine("Token: {0}", reader.TokenType);
}
}
How do I read from a file and set it as a string that can be handled by the code above? It sounds like a basic question but I'm still struggling with this after several hours. All I've seen expects that you know the structure of the Json file and I don't in this case.
This is the exact use case that dynamic and ExpandoObject were made for! Here you can deserialize the JSON to an object, then traverse the object's properties (look up online how to work with ExpandoObjects).
var expandoConverter = new ExpandoObjectConverter();
dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(json, expandoConverter);
Or, if you were just looking to read the json from disk as a string, then use string json = File.ReadAllText(filePathAndName);
The above code snippet requires installing the package NewtonSoft.
Eriks answer was great to mention the ExpandoObject, dynamic and File call. It got my +1.
I'm adding to ErikEs answer to include the package and include details required for a minimal running program.
This code was in my Program.cs file for a Console App project type in Visual Studio 2017. You should also run install-package newtonsoft.json in the Package Manager Console. This command will load newtonsoft.json.11.0.1 pakcage. .Net Framework was 4.6.1.
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Dynamic;
using System.IO;
namespace ReadJson
{
class Program
{
static void Main(string[] args)
{
string filePath = "<full path to json file>";
string json = File.ReadAllText(filePath);
var expandoConverter = new ExpandoObjectConverter();
dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(json, expandoConverter);
//do more with your dynamic object here...
}
}
}
Related
I'm working with creating JsonPatchDocuments (MSDN) in .NET (as opposed to just accepting through an endpoint). I would really like to be able to use System.Text.Json for this as opposed to Newtonsoft.JSON, but I can't figure out equivalent functionality. Microsoft guidance on replacing JObject does not seem to cover this behavior from what I can tell.
At this point in the code I have worked through a JsonDocument, and identified a JsonElement that is new and needs to be added to the patch.
Pulling from the RFC, here are two example documents and their JSON patch:
Start: { "foo": "bar" }
Patch: [{ "op": "add", "path": "/child", "value": { "grandchild": { } } }]
End: {"foo": "bar","child": {"grandchild": { } } }
I tried a number of different varieties and didn't save them all. But here are some ways to not successfully accomplish this:
using System.Text.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Microsoft.AspNetCore.JsonPatch;
// JsonElement element is the change we want to see added in the patch
JsonPatchDocument patchDocument = new JsonPatchDocument();
patchDocument.Add(path, element); // Only the JsonElement property comes through. Gives [{"value":{"ValueKind":1},"path":"/child","op":"add"}]
patchDocument.Add(path, element.GetRawText()); // Obviously treated as a string so fails and gives [{"value":"{\n \"grandchild\": {\n }\n }","path":"/child","op":"add"}]
patchDocument.Add(path, element.GetString()); // Similar to the above attempt, but fails because element is an Object and throws exception. Attempting to replicate Newtonsoft's ToObject gives the next example
patchDocument.Add(path, netjson.JsonSerializer.Deserialize<object>(element.GetRawText())); // Just a more convoluted version of our first attempt. Gives [{"value":{"ValueKind":1},"path":"/child","op":"add"}]
Here is working code that uses Newtonsoft.Json to take my JsonElement and produce the correct patch output. (but is very gross)
JsonPatchDocument patchDocument = new JsonPatchDocument();
JsonDocument newDocument = JsonDocument.Parse("{ \"foo\": \"bar\", \"child\": {\"grandchild\": { } } }");
JsonElement parentObject = newDocument.RootElement;
JsonElement element = parentObject.GetProperty("child");
// This is more dynamic in real code, but hardcoded for example
patchDocument.Add("/", JObject.Parse(parentObject.GetRawText()).Property("child").Value); // Correct answer [{\"value\":{\"grandchild\":{}},\"path\":\"/\",\"op\":\"add\"}]
I can (and for the moment am) proceeding just using Newtonsoft.Json. But as that isn't really supposed to be the way of the future - is there a way to successfully provide the correct value to JsonPatchDocument.Add using System.Text.Json?
I am looking for some help with regards to Parsing the the value "mppdemo" in the below json file (See screenshot)
{
"client":{
"isWebLogin":false,
"registryName": "mpdemo",
"walletCode": "Local"
}
}
I have done some research in and arround the webs but alot of the examples wither are out dated or dont work.
This is what i have tried
//JObject T = JObject.Parse(File.ReadAllText(DownloadConfigFilelocation));
var source = File.ReadAllText(DownloadConfigFilelocation);
var JavaScriptSerializer MySerializer = new JavaScriptSerializer();
var myObj = MySerializer.Deserialize<T>(source);
var RegistryName = myObj.searchResults[0].hotelID;
MessageBox.Show(RegistryName);
The above doesnt pick up the JavaScriptSerializer function from the library even though im using the using System.Web.Script.Serialization;
Can someone help me get this code segment to work
I hope i have provided enough info
EDIT: I just realized that you're having another problem - that your compiler does not recognize the System.Web.Script.Serialization.JavaScriptSerializer type. You'll need to add a reference to System.Web.Extensions.dll to your project. I don't know what IDE you are using, but for example in SharpDevelop you can right click References > Add Reference > in filter start typing "System.Web.Extensions" > among results find "System.Web.Extensions" and double click it (it will be moved to lower window) > hit OK and compile your project.
If you still want to use System.Web.Script.Serialization.JavaScriptSerializer, I'd probably do it like this:
using System;
using System.Text.RegularExpressions;
using System.Web.Script.Serialization;
namespace jsonhratky
{
public static class Program {
public static void Main(string[] args)
{
var instance = new JsonParsingTest();
}
}
public class JsonParsingTest
{
class Response {
public Client client;
}
class Client {
public bool isWebLogin;
public string registryName;
public string walletCode;
}
const string JSON_EXAMPLE = ("{" + ("\"client\":{" + ("\"isWebLogin\":false," + ("\"registryName\": \"mpdemo\"," + ("\"walletCode\": \"Local\"" + ("}" + "}"))))));
public JsonParsingTest() {
// Solution #1 using JavaScriptSerializer
var serializer = new JavaScriptSerializer();
Response parsed = serializer.Deserialize<Response>(JSON_EXAMPLE);
Console.WriteLine("parsed isWebLogin: " + parsed.client.isWebLogin);
Console.WriteLine("parsed registryName: " + parsed.client.registryName);
Console.WriteLine("parsed walletCode: " + parsed.client.walletCode);
// Solution #2 (not recommended)
var matches = Regex.Match(JSON_EXAMPLE, "registryName\":.*?\"([^\"]+)\"", RegexOptions.Multiline);
if (matches.Success) {
Console.WriteLine("registryName parsed using Regex: " + matches.Groups[1].Value);
} else {
Console.WriteLine("Solution using Regex failed.");
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}
You need to create a "POJO" class (there's probably another term in C# for plain old classes) with fields matching those in your string response. Since your fields isWebLogin, registryName and walletCode are not directly part of main object (Response) but they belong to sub-class (Client), you need two classes: Response (or call it whatever you want) and then the field "client" must match string in response (as well as the fields of the sub-class).
Result:
Anyway, I also included a solution using Regex, but I absolutely don't recommend that. It's suitable only as a workaround and only then if you know that your response will never contain more than one "client" objects.
The problem seems to be in this line of your code var myObj = MySerializer.Deserialize<T>(source); You need to give the type of object instead of T.
I have simple C# object instantiated like
User theUser = new User("John", "Doe");
now I need to load it to my Node.js file like:
var theUser = {name:"John", lastName:"Doe"};
Can you please let me know how to do that? Do I have to save/write the output on a separate json file? or..?
Thanks
If you intend to use JSON as bridge from C# to Nodejs, use JavaScriptSerializer class to convert your C# class as JSON data.
https://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer.aspx
C#
// your data class
public class YourClassName
{
...
}
// Javascript serialization
using System.IO;
using System.Web.Script.Serialization;
String json = new JavaScriptSerializer().Serialize(YourClassName);
File.WriteAllText("json_file_path", json);
Node.js
// Async mode
var jsondata = require('fs').readFile('json_file_path', 'utf8', function (err, data) {
if (err) throw err; // throw error if not found or invalid
var obj = JSON.parse(jsondata);
});
// Sync mode
var jsondata = JSON.parse(require('fs').readFileSync('json_file_path', 'utf8'));
Node.js reference: How to parse JSON using Node.js?
Hopefully this is useful, CMIIW.
Why not just use Newtonsoft.Json - add a reference to this within your project.
To convert the object from a known type to json string;
string output = JsonConvert.SerializeObject(theUser);
To convert the object to a dynamic type;
dynamic json = JToken.Parse(theUser); - to dynamic
MSDN Link for extra help, if needed.
I need to write the following data into a text file using JSON format in C#. The brackets are important for it to be valid JSON format.
[
{
"Id": 1,
"SSN": 123,
"Message": "whatever"
},
{
"Id": 2,
"SSN": 125,
"Message": "whatever"
}
]
Here is my model class:
public class data
{
public int Id { get; set; }
public int SSN { get; set; }
public string Message { get; set;}
}
Update 2020: It's been 7 years since I wrote this answer. It still seems to be getting a lot of attention. In 2013 Newtonsoft Json.Net was THE answer to this problem. Now it's still a good answer to this problem but it's no longer the the only viable option. To add some up-to-date caveats to this answer:
.NET Core now has the spookily similar System.Text.Json serializer (see below)
The days of the JavaScriptSerializer have thankfully passed and this class isn't even in .NET Core. This invalidates a lot of the comparisons ran by Newtonsoft.
It's also recently come to my attention, via some vulnerability scanning software we use in work that Json.Net hasn't had an update in some time. Updates in 2020 have dried up and the latest version, 12.0.3, is over a year old (2021).
The speed tests (previously quoted below but now removed as they are so out of date that they seem irrelevant) are comparing an older version of Json.Net (version 6.0 and like I said the latest is 12.0.3) with an outdated .Net Framework serialiser.
One advantage the System.Text.Json serializer has over Newtonsoft is it's support for async/await
Are Json.Net's days numbered? It's still used a LOT and it's still used by MS libraries. So probably not. But this does feel like the beginning of the end for this library that may well of just run it's course.
.NET Core 3.0+ and .NET 5+
A new kid on the block since writing this is System.Text.Json which has been added to .Net Core 3.0. Microsoft makes several claims to how this is, now, better than Newtonsoft. Including that it is faster than Newtonsoft. I'd advise you to test this yourself .
Examples:
using System.Text.Json;
using System.Text.Json.Serialization;
List<data> _data = new List<data>();
_data.Add(new data()
{
Id = 1,
SSN = 2,
Message = "A Message"
});
string json = JsonSerializer.Serialize(_data);
File.WriteAllText(#"D:\path.json", json);
or
using System.Text.Json;
using System.Text.Json.Serialization;
List<data> _data = new List<data>();
_data.Add(new data()
{
Id = 1,
SSN = 2,
Message = "A Message"
});
await using FileStream createStream = File.Create(#"D:\path.json");
await JsonSerializer.SerializeAsync(createStream, _data);
Documentation
Newtonsoft Json.Net (.Net framework and .Net Core)
Another option is Json.Net, see example below:
List<data> _data = new List<data>();
_data.Add(new data()
{
Id = 1,
SSN = 2,
Message = "A Message"
});
string json = JsonConvert.SerializeObject(_data.ToArray());
//write string to file
System.IO.File.WriteAllText(#"D:\path.txt", json);
Or the slightly more efficient version of the above code (doesn't use a string as a buffer):
//open file stream
using (StreamWriter file = File.CreateText(#"D:\path.txt"))
{
JsonSerializer serializer = new JsonSerializer();
//serialize object directly into file stream
serializer.Serialize(file, _data);
}
Documentation: Serialize JSON to a file
The example in Liam's answer saves the file as string in a single line. I prefer to add formatting. Someone in the future may want to change some value manually in the file. If you add formatting it's easier to do so.
The following adds basic JSON indentation:
string json = JsonConvert.SerializeObject(_data.ToArray(), Formatting.Indented);
There is built in functionality for this using the JavaScriptSerializer Class:
var json = JavaScriptSerializer.Serialize(data);
var responseData = //Fetch Data
string jsonData = JsonConvert.SerializeObject(responseData, Formatting.None);
System.IO.File.WriteAllText(Server.MapPath("~/JsonData/jsondata.txt"), jsonData);
I had asked this question before. The solution using Newtonsoft worked great until I deployed the website on web hosting server, where its giving me nightmares. Therefore, I am planning to use some System.Web libraries so that I don't have to deal with *.dlls and such and I can easily deploy my website.
Can someone help me parse the same json output using System.Web.Script.Serialization or any System library? Thanks a lot.
I hope your real json string is valid since the one you posted is corrupted but Json.Net tolerates it.
The only trick is deserializing to this funny type List<Dictionary<string,object>>
Here is an example with corrected json(removed trailing ,s)
string json = #"[ { ""ew"" : ""bharat"", ""hws"" : [ ""\u092D\u093E\u0930\u0924"",""\u092D\u0930\u0924"",""\u092D\u0930\u093E\u0924"",""\u092D\u093E\u0930\u093E\u0924"",""\u092C\u0939\u0930\u0924"" ] }, { ""ew"" : ""india"", ""hws"" : [ ""\u0907\u0902\u0921\u093F\u092F\u093E"",""\u0907\u0928\u094D\u0921\u093F\u092F\u093E"",""\u0907\u0923\u094D\u0921\u093F\u092F\u093E"",""\u0908\u0928\u094D\u0921\u093F\u092F\u093E"",""\u0907\u0928\u0921\u093F\u092F\u093E"" ] } ]";
var list = new JavaScriptSerializer().Deserialize<List<Dictionary<string,object>>>(json);
foreach (var dict in list)
{
var ew = (string)dict["ew"];
var firstValOfHws = ((ArrayList)dict["hws"])[0];
}
--EDIT--
OK, This should work
var serializer = new DataContractJsonSerializer(typeof(List<Result>));
var result = (List<Result>)serializer.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(json)));
public class Result
{
public string ew;
public List<string> hws;
}