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);
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'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...
}
}
}
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.
As the title says the deserialization fail after protecting my application with themida with the following exception :
Unable to generate a temporary class (result=1).
error CS0009: Metadata file 'c:\Path\to\protected.exe' could not be opened -- 'An attempt was made to load a program with an incorrect format. '
Here's the code I'm using for the deserialization (It works when the exe is not protected):
MyClass myClass;
try
{
using (var stream = new MemoryStream(Data))
{
var serializer = new XmlSerializer(typeof(ComSec.MyClass));
myClass = serializer.Deserialize(stream) as MyClass;
}
}
catch (Exception e)
{
return null;
}
Weird thing is that the code + themida protection works fine on my machine but it fails on the VM and on a co-worker's machine
I'm using (same config as my co-worker) :
VS2012 Professional
Windows 7 x64 Ultimate
Themida 2.1.2.0 x86 (With .Net support)
The VM is a fresh install of Windows 7 x86.
I ended up using the DataContract attribute and using a DataContractSerializer to Serialize and deserialize the object (It works now everywhere and with/without the protection ).
My research:
[DataContract(Name = "TestClass")]
public class TestClass
{
[DataMember(Name = "Name")]
public string Name { get; set; }
[DataMember(Name = "Age")]
public int Age { get; set; }
}
Serialization/Deserialization :
var serializer = new DataContractSerializer(typeof(TestClass));
using (var stream = new MemoryStream())
{
serializer.WriteObject(stream, this);
File.WriteAllBytes("TestClass.xml", stream.ToArray());
}
TestClass o = null;
using (var stream = new MemoryStream(File.ReadAllBytes("TestClass.xml")))
{
o = serializer.ReadObject(stream) as TestClass;
}
I experienced this issue as well and the proposed answer worked fine. The original problem was due to file access permissions. Just adding this information so other people understand why DataContract works (from https://stackoverflow.com/a/10340155/1111380):
DataContractSerializer, NetDataContractSerializer and DataContractJsonSerializer do NOT require disk space and do NOT emit assemblies to disk. Instead, they generate IL on the fly (in memory) and use it during subsequent serialization episodes to do serialization and deserialization all within the AppDomain they're operating in. However, XmlSerializer does require disk space and explains the error (path to the file could not be opened/access).
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;
}