I am using HTTPCLient to call RestFul service. My problem when parsing DateTime.
Because in my class I have DateTime Property. Which in Json it is type long. Json key is: exp
{
"resultCodes": "OK",
"description": "OK",
"pans": {
"maskedPan": [
{
"id": "4b533683-bla-bla-3517",
"pan": "67*********98",
"exp": 1446321600000,
"isDefault": true
},
{
"id": "a3093f00-zurna-01e18a8d4d72",
"pan": "57*********96",
"exp": 1554058800000,
"isDefault": false
}
]
}
}
In documentation i read that
To minimize memory usage and the number of objects allocated Json.NET supports serializing and deserializing directly to a stream.
So =>
WAY 1 (Reading via GetStringAsync). In documentation has written that use StreamReader instead.
return Task.Factory.StartNew(() =>
{
var client = new HttpClient(_handler);
var url = String.Format(_baseUrl + #"list/{0}", sessionId);
BillsList result;
var rrrrr = client.GetStringAsync(url).Result;
result = JsonConvert.DeserializeObject<BillsList>(rrrrr,
new MyDateTimeConverter());
return result;
}, cancellationToken);
WAY 2(Good way. I read via StreamReader. Bu in line var rTS = sr.ReadToEnd(); it creates new string. It is not good. Because i have used GetStreamAsync to avoid of creating string variable.)
return Task.Factory.StartNew(() =>
{
var client = new HttpClient(_handler);
var url = String.Format(_baseUrl + #"list/{0}", sessionId);
BillsList result;
using (var s = client.GetStreamAsync(url).Result)
using (var sr = new StreamReader(s))
using (JsonReader reader = new JsonTextReader(sr))
{
var rTS = sr.ReadToEnd();
result = JsonConvert.DeserializeObject<BillsList>(rTS,
new MyDateTimeConverter());
}
return result;
}, cancellationToken);
WAY 3(The best. But it gives exception if property is DateTime in my class. )
return Task.Factory.StartNew(() =>
{
var client = new HttpClient(_handler);
var url = String.Format(_baseUrl + #"list/{0}", sessionId);
BillsList result;
using (var s = client.GetStreamAsync(url).Result)
using (var sr = new StreamReader(s))
using (JsonReader reader = new JsonTextReader(sr))
{
var serializer = new JsonSerializer();
result = serializer.Deserialize<BillsList>(reader);
}
return result;
}, cancellationToken);
So my question. I want to continue with 3-rd way. But have there any way to set some handler as MyDateTimeConverter for JsonSerializer to convert it automatically?
You can set up default JsonSerializerSettings when your app is initialized:
// This needs to be done only once, so put it in an appropriate static initializer.
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
Converters = new List<JsonConverter> { new MyDateTimeConverter() }
};
Then later you can use JsonSerializer.CreateDefault
JsonSerializer serializer = JsonSerializer.CreateDefault();
result = serializer.Deserialize<BillsList>(reader);
You can add your MyDateTimeConverter to the Converters collection on the JsonSerializer; that should allow you to use your third approach without getting errors.
var serializer = new JsonSerializer();
serializer.Converters.Add(new MyDateTimeConverter());
result = serializer.Deserialize<BillsList>(reader);
Related
I'm using System.Text.Json.Nodes in .NET 6.0 and what I'm trying to do is simple: Copy a JsonNode from one and attach the node to another JsonNode.
The following is my code.
public static string concQuest(string input, string allQuest, string questId) {
JsonNode inputNode = JsonNode.Parse(input)!;
JsonNode allQuestNode = JsonNode.Parse(allQuest)!;
JsonNode quest = allQuestNode.AsArray().First(quest =>
quest!["id"]!.GetValue<string>() == questId) ?? throw new KeyNotFoundException("No matching questId found.");
inputNode["quest"] = quest; // Exception occured
return inputNode.ToJsonString(options);
}
But when I try to run it, I got a System.InvalidOperationException said "The node already has a parent."
I've tried edit
inputNode["quest"] = quest;
to
inputNode["quest"] = quest.Root; // quest.Root is also a JsonNode
Then the code runs well but it returns all nodes instead of the one I specified which is not the result I want. Also since the code works fine, I think it is feasible to set a JsonNode to another one directly.
According to the exception message, it seems if I want to add a JsonNode to another one, I must unattach it from its parent first, but how can I do this?
Note that my JSON file is quite big (more than 6MB), so I want to ensure there are no performance issues with my solution.
Easiest option would be to convert json node into string and parse it again (though possibly not the most performant one):
var destination = #"{}";
var source = "[{\"id\": 1, \"name\":\"some quest\"},{}]";
var sourceJson = JsonNode.Parse(source);
var destinationJson = JsonNode.Parse(destination);
var quest = sourceJson.AsArray().First();
destinationJson["quest"] = JsonNode.Parse(quest.ToJsonString());
Console.WriteLine(destinationJson.ToJsonString(new() { WriteIndented = true }));
Will print:
{
"quest": {
"id": 1,
"name": "some quest"
}
}
UPD
Another trick is to deserialize the JsonNode to JsonNode:
...
var quest = sourceJson.AsArray().First();
var clone = quest.Deserialize<JsonNode>();
clone["name"] = "New name";
destinationJson["quest"] = clone;
Console.WriteLine(quest["name"]);
Console.WriteLine(destinationJson.ToJsonString(new() { WriteIndented = true }));
Prints:
some quest
{
"quest": {
"id": 1,
"name": "New name"
}
}
As JsonNode has no Clone() method as of .NET 6, the easiest way to copy it is probably to invoke the serializer's JsonSerializer.Deserialize<TValue>(JsonNode, JsonSerializerOptions) extension method to deserialize your node directly into another node. First, introduce the following extension methods to copy or move a node:
public static partial class JsonExtensions
{
public static TNode? CopyNode<TNode>(this TNode? node) where TNode : JsonNode => node?.Deserialize<TNode>();
public static JsonNode? MoveNode(this JsonArray array, int id, JsonObject newParent, string name)
{
var node = array[id];
array.RemoveAt(id);
return newParent[name] = node;
}
public static JsonNode? MoveNode(this JsonObject parent, string oldName, JsonObject newParent, string name)
{
parent.Remove(oldName, out var node);
return newParent[name] = node;
}
public static TNode ThrowOnNull<TNode>(this TNode? value) where TNode : JsonNode => value ?? throw new JsonException("Null JSON value");
}
Now your code may be written as follows:
public static string concQuest(string input, string allQuest, string questId)
{
var inputObject = JsonNode.Parse(input).ThrowOnNull().AsObject();
var allQuestArray = JsonNode.Parse(allQuest).ThrowOnNull().AsArray();
concQuest(inputObject, allQuestArray, questId);
return inputObject.ToJsonString();
}
public static JsonNode? concQuest(JsonObject inputObject, JsonArray allQuestArray, string questId)
{
// Enumerable.First() will throw an InvalidOperationException if no element is found satisfying the predicate.
var node = allQuestArray.First(quest => quest!["id"]!.GetValue<string>() == questId);
return inputObject["quest"] = node.CopyNode();
}
Alternatively, if you aren't going to keep your array of quests around, you could just move the node from the array to the target like so:
public static string concQuest(string input, string allQuest, string questId)
{
var inputObject = JsonNode.Parse(input).ThrowOnNull().AsObject();
var allQuestArray = JsonNode.Parse(allQuest).ThrowOnNull().AsArray();
concQuest(inputObject, allQuestArray, questId);
return inputObject.ToJsonString();
}
public static JsonNode? concQuest(JsonObject inputObject, JsonArray allQuestArray, string questId)
{
// Enumerable.First() will throw an InvalidOperationException if no element is found satisfying the predicate.
var (_, index) = allQuestArray.Select((quest, index) => (quest, index)).First(p => p.quest!["id"]!.GetValue<string>() == questId);
return allQuestArray.MoveNode(index, inputObject, "quest");
}
Also, you wrote
since my json file is quite big (more than 6MB), I was worried there might be some performance issues.
In that case I would avoid loading the JSON files into the input and allQuest strings because strings larger than 85,000 bytes go on the large object heap which can cause subsequent performance degradation. Instead, deserialize directly from the relevant files into JsonNode arrays and objects like so:
var questId = "2"; // Or whatever
JsonArray allQuest;
using (var stream = new FileStream(allQuestFileName, new FileStreamOptions { Mode = FileMode.Open, Access = FileAccess.Read }))
allQuest = JsonNode.Parse(stream).ThrowOnNull().AsArray();
JsonObject input;
using (var stream = new FileStream(inputFileName, new FileStreamOptions { Mode = FileMode.Open, Access = FileAccess.Read }))
input = JsonNode.Parse(stream).ThrowOnNull().AsObject();
JsonExtensions.concQuest(input, allQuest, questId);
using (var stream = new FileStream(inputFileName, new FileStreamOptions { Mode = FileMode.Create, Access = FileAccess.Write }))
using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }))
input.WriteTo(writer);
Or, if your app is asynchronous, you can do:
JsonArray allQuest;
await using (var stream = new FileStream(allQuestFileName, new FileStreamOptions { Mode = FileMode.Open, Access = FileAccess.Read, Options = FileOptions.Asynchronous }))
allQuest = (await JsonSerializer.DeserializeAsync<JsonArray>(stream)).ThrowOnNull();
JsonObject input;
await using (var stream = new FileStream(inputFileName, new FileStreamOptions { Mode = FileMode.Open, Access = FileAccess.Read, Options = FileOptions.Asynchronous }))
input = (await JsonSerializer.DeserializeAsync<JsonObject>(stream)).ThrowOnNull();
JsonExtensions.concQuest(input, allQuest, questId);
await using (var stream = new FileStream(inputFileName, new FileStreamOptions { Mode = FileMode.Create, Access = FileAccess.Write, Options = FileOptions.Asynchronous }))
await JsonSerializer.SerializeAsync(stream, input, new JsonSerializerOptions { WriteIndented = true });
Notes:
Microsoft's documentation explicitly recommends against serializing from and to strings instead of UTF-8 byte sequences for performance reasons which is another reason not to load your large JSON files into temporary string buffers.
Demo fiddles:
For copying the node, see https://dotnetfiddle.net/cwKDen.
For moving the node, see https://dotnetfiddle.net/cI8DuB.
For async reading and writing, see https://dotnetfiddle.net/VjKstQ
I have 200.000 json files on file system.
Deserializing them one-by-one and putting them in a List takes about 4 minutes.
I am looking for fastest way to deserialize them or a way to deserialize them all at once.
Code Sample
The code i am using is somthing like this:
var files = Directory.GetFiles(#"C:\Data","*.json");
var list = new List<ParsedData>();
var dt1 = DateTime.Now;
foreach(var file in files)
{
using (StreamReader filestr = File.OpenText(file))
{
JsonSerializer serializer = new JsonSerializer();
var data= (ParsedData)serializer.Deserialize(filestr, typeof(ParsedData));
list.Add(data);
}
}
var dt2 = DateTime.Now;
Console.WriteLine((dt2 - dt1).TotalMilliseconds);
JSON format
And the json sample is:
{
"channel_name": "#channel",
"message": "",
"text": "",
"date": "2015/10/09 12:22:48",
"views": "83810",
"forwards": "0",
"raw_text": "",
"keywords_marked": "",
"id": 973,
"media": "1.jpg"
}
You can trying using a Parallel.Foreach():
var files = Directory.GetFiles(#"C:\Data", "*.json");
var list = new ConcurrentBag<ParsedData>();
var dt1 = DateTime.Now;
Parallel.ForEach(files, (file) =>
{
var filestr = File.ReadAllText(file);
var data = JsonSerializer.Deserialize<ParsedData>(filestr);
list.Add(data);
});
var dt2 = DateTime.Now;
Console.WriteLine((dt2 - dt1).TotalMilliseconds);
EDIT:
Remove var files = Directory.GetFiles(#"C:\Data", "*.json"); and then try directly:
Parallel.ForEach(Directory.EnumerateFiles(#"C:\Data", "*.json"), (file) =>
{
var filestr = File.ReadAllText(file);
var data = JsonSerializer.Deserialize<ParsedData>(filestr);
list.Add(data);
});
But with 200000 files 50sec seems pretty descent.
If you use .NET6, you may use:
Parallel.ForEachAsync( ... async(file) => {
var fs = new FileStream(file, FileMode.Open);
var data = await JsonSerializer.DeserializeAsync<ParsedData>(fs);
list.Add(data);
});
I am writing an unit test and have to return response object. I was able to to return below response
var res = new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(string.Format("{{ 'email':'{0}', 'first_name':'{1}', 'last_name':'{2}', 'id':'{3}' }}", data.Email, data.FirstName, data.LastName, data.Id))
};
but now need to wrap all response in 'data' property. For this updated code like below
var res = new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(string.Format("{{'data':{'email':'{0}','first_name':'{1}','last_name':'{2}','id':'{3}'}}}", data.Email, data.FirstName, data.LastName, data.Id))
};
but getting below error
Message:
System.FormatException : Input string was not in a correct format.
Stack Trace:
StringBuilder.FormatError()
StringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args)
String.FormatHelper(IFormatProvider provider, String format, ParamsArray args)
String.Format(String format, Object[] args)
Not sure whats wrong here. Please help.
You may use Newtonsoft.Json
using System;
using Newtonsoft.Json;
using System.Text;
using System.IO;
public class Program
{
public static void Main()
{
var data = new
{
email = "data#ada.com",
first_name = "abc",
last_name = "abc",
id = 1
};
var data1 = new {data};
var s = new JsonSerializer();
var sb = new StringBuilder();
using (var w = new StringWriter(sb))
{
s.Serialize(w, data1);
}
Console.WriteLine(sb.ToString());
}
}
I didn't have much time to look but can you try this ?
var res = new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(string.Format("{{'data':{'email':'{0}','first_name':'{1}','last_name':'{2}','id':'{3}'}}}", data.data.Email, data.data.FirstName, data.data.LastName, data.data.Id))
};
Tried lot of options and ended with below.
string.Format("{{ 'data': {{ 'email':'{0}', 'first_name':'{1}', 'last_name':'{2}', 'id':'{3}' }} }}", data.Email, data.FirstName, data.LastName, data.Id);
If you are avoiding serializing, you can use c# 7.0 feature $ string interpolation.
Use:
var res = new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent($"{{ 'data': {{ 'email':'{data.Email}', 'first_name':'{data.FirstName}', 'last_name':'{data.LastName}', 'id':'{data.Id}' }} }}")
};
I often need to extend my Domain model with additional info before returning it to the client with WebAPI. To avoid creation of ViewModel I thought I could return JObject with additional properties. I could not however find direct way to convert object of any type to JObject with single call to Newtonsoft JSON library. I came up with something like this:
first SerializeObject
then Parse
and extend JObject
Eg.:
var cycles = cycleSource.AllCycles();
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
var vm = new JArray();
foreach (var cycle in cycles)
{
var cycleJson = JObject.Parse(JsonConvert.SerializeObject(cycle, settings));
// extend cycleJson ......
vm.Add(cycleJson);
}
return vm;
I this correct way ?
JObject implements IDictionary, so you can use it that way. For ex,
var cycleJson = JObject.Parse(#"{""name"":""john""}");
//add surname
cycleJson["surname"] = "doe";
//add a complex object
cycleJson["complexObj"] = JObject.FromObject(new { id = 1, name = "test" });
So the final json will be
{
"name": "john",
"surname": "doe",
"complexObj": {
"id": 1,
"name": "test"
}
}
You can also use dynamic keyword
dynamic cycleJson = JObject.Parse(#"{""name"":""john""}");
cycleJson.surname = "doe";
cycleJson.complexObj = JObject.FromObject(new { id = 1, name = "test" });
If you have an object and wish to become JObject you can use:
JObject o = (JObject)JToken.FromObject(miObjetoEspecial);
like this :
Pocion pocionDeVida = new Pocion{
tipo = "vida",
duracion = 32,
};
JObject o = (JObject)JToken.FromObject(pocionDeVida);
Console.WriteLine(o.ToString());
// {"tipo": "vida", "duracion": 32,}
This will work:
var cycles = cycleSource.AllCycles();
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
var vm = new JArray();
foreach (var cycle in cycles)
{
var cycleJson = JObject.FromObject(cycle);
// extend cycleJson ......
vm.Add(cycleJson);
}
return vm;
JObject.FromObject(obj);
Documentation here
I am using .NET JSON parser and would like to serialize my config file so it is readable. So instead of:
{"blah":"v", "blah2":"v2"}
I would like something nicer like:
{
"blah":"v",
"blah2":"v2"
}
My code is something like this:
using System.Web.Script.Serialization;
var ser = new JavaScriptSerializer();
configSz = ser.Serialize(config);
using (var f = (TextWriter)File.CreateText(configFn))
{
f.WriteLine(configSz);
f.Close();
}
You are going to have a hard time accomplishing this with JavaScriptSerializer.
Try JSON.Net.
With minor modifications from JSON.Net example
using System;
using Newtonsoft.Json;
namespace JsonPrettyPrint
{
internal class Program
{
private static void Main(string[] args)
{
Product product = new Product
{
Name = "Apple",
Expiry = new DateTime(2008, 12, 28),
Price = 3.99M,
Sizes = new[] { "Small", "Medium", "Large" }
};
string json = JsonConvert.SerializeObject(product, Formatting.Indented);
Console.WriteLine(json);
Product deserializedProduct = JsonConvert.DeserializeObject<Product>(json);
}
}
internal class Product
{
public String[] Sizes { get; set; }
public decimal Price { get; set; }
public DateTime Expiry { get; set; }
public string Name { get; set; }
}
}
Results
{
"Sizes": [
"Small",
"Medium",
"Large"
],
"Price": 3.99,
"Expiry": "\/Date(1230447600000-0700)\/",
"Name": "Apple"
}
Documentation: Serialize an Object
A shorter sample code for Json.Net library
private static string FormatJson(string json)
{
dynamic parsedJson = JsonConvert.DeserializeObject(json);
return JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
}
If you have a JSON string and want to "prettify" it, but don't want to serialise it to and from a known C# type then the following does the trick (using JSON.NET):
using System;
using System.IO;
using Newtonsoft.Json;
class JsonUtil
{
public static string JsonPrettify(string json)
{
using (var stringReader = new StringReader(json))
using (var stringWriter = new StringWriter())
{
var jsonReader = new JsonTextReader(stringReader);
var jsonWriter = new JsonTextWriter(stringWriter) { Formatting = Formatting.Indented };
jsonWriter.WriteToken(jsonReader);
return stringWriter.ToString();
}
}
}
Shortest version to prettify existing JSON: (edit: using JSON.net)
JToken.Parse("mystring").ToString()
Input:
{"menu": { "id": "file", "value": "File", "popup": { "menuitem": [ {"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}, {"value": "Close", "onclick": "CloseDoc()"} ] } }}
Output:
{
"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{
"value": "New",
"onclick": "CreateNewDoc()"
},
{
"value": "Open",
"onclick": "OpenDoc()"
},
{
"value": "Close",
"onclick": "CloseDoc()"
}
]
}
}
}
To pretty-print an object:
JToken.FromObject(myObject).ToString()
Oneliner using Newtonsoft.Json.Linq:
string prettyJson = JToken.Parse(uglyJsonString).ToString(Formatting.Indented);
Net Core App
var js = JsonSerializer.Serialize(obj, new JsonSerializerOptions {
WriteIndented = true
});
All this can be done in one simple line:
string jsonString = JsonConvert.SerializeObject(yourObject, Formatting.Indented);
Here is a solution using Microsoft's System.Text.Json library:
static string FormatJsonText(string jsonString)
{
using var doc = JsonDocument.Parse(
jsonString,
new JsonDocumentOptions
{
AllowTrailingCommas = true
}
);
MemoryStream memoryStream = new MemoryStream();
using (
var utf8JsonWriter = new Utf8JsonWriter(
memoryStream,
new JsonWriterOptions
{
Indented = true
}
)
)
{
doc.WriteTo(utf8JsonWriter);
}
return new System.Text.UTF8Encoding()
.GetString(memoryStream.ToArray());
}
You may use following standard method for getting formatted Json
JsonReaderWriterFactory.CreateJsonWriter(Stream stream, Encoding encoding, bool ownsStream, bool indent, string indentChars)
Only set "indent==true"
Try something like this
public readonly DataContractJsonSerializerSettings Settings =
new DataContractJsonSerializerSettings
{ UseSimpleDictionaryFormat = true };
public void Keep<TValue>(TValue item, string path)
{
try
{
using (var stream = File.Open(path, FileMode.Create))
{
//var currentCulture = Thread.CurrentThread.CurrentCulture;
//Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
try
{
using (var writer = JsonReaderWriterFactory.CreateJsonWriter(
stream, Encoding.UTF8, true, true, " "))
{
var serializer = new DataContractJsonSerializer(type, Settings);
serializer.WriteObject(writer, item);
writer.Flush();
}
}
catch (Exception exception)
{
Debug.WriteLine(exception.ToString());
}
finally
{
//Thread.CurrentThread.CurrentCulture = currentCulture;
}
}
}
catch (Exception exception)
{
Debug.WriteLine(exception.ToString());
}
}
Pay your attention to lines
var currentCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
....
Thread.CurrentThread.CurrentCulture = currentCulture;
For some kinds of xml-serializers you should use InvariantCulture to avoid exception during deserialization on the computers with different Regional settings. For example, invalid format of double or DateTime sometimes cause them.
For deserializing
public TValue Revive<TValue>(string path, params object[] constructorArgs)
{
try
{
using (var stream = File.OpenRead(path))
{
//var currentCulture = Thread.CurrentThread.CurrentCulture;
//Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
try
{
var serializer = new DataContractJsonSerializer(type, Settings);
var item = (TValue) serializer.ReadObject(stream);
if (Equals(item, null)) throw new Exception();
return item;
}
catch (Exception exception)
{
Debug.WriteLine(exception.ToString());
return (TValue) Activator.CreateInstance(type, constructorArgs);
}
finally
{
//Thread.CurrentThread.CurrentCulture = currentCulture;
}
}
}
catch
{
return (TValue) Activator.CreateInstance(typeof (TValue), constructorArgs);
}
}
Thanks!
Using System.Text.Json set JsonSerializerOptions.WriteIndented = true:
JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true };
string json = JsonSerializer.Serialize<Type>(object, options);
2023 Update
For those who ask how I get formatted JSON in .NET using C# and want to see how to use it right away and one-line lovers. Here are the indented JSON string one-line codes:
There are 2 well-known JSON formatter or parsers to serialize:
Newtonsoft Json.Net version:
using Newtonsoft.Json;
var jsonString = JsonConvert.SerializeObject(yourObj, Formatting.Indented);
.Net 7 version:
using System.Text.Json;
var jsonString = JsonSerializer.Serialize(yourObj, new JsonSerializerOptions { WriteIndented = true });
using System.Text.Json;
...
var parsedJson = JsonSerializer.Deserialize<ExpandoObject>(json);
var options = new JsonSerializerOptions() { WriteIndented = true };
return JsonSerializer.Serialize(parsedJson, options);
First I wanted to add comment under Duncan Smart post, but unfortunately I have not got enough reputation yet to leave comments. So I will try it here.
I just want to warn about side effects.
JsonTextReader internally parses json into typed JTokens and then serialises them back.
For example if your original JSON was
{ "double":0.00002, "date":"\/Date(1198908717056)\/"}
After prettify you get
{
"double":2E-05,
"date": "2007-12-29T06:11:57.056Z"
}
Of course both json string are equivalent and will deserialize to structurally equal objects, but if you need to preserve original string values, you need to take this into concideration
I have something very simple for this. You can put as input really any object to be converted into json with a format:
private static string GetJson<T> (T json)
{
return JsonConvert.SerializeObject(json, Formatting.Indented);
}
This worked for me. In case someone is looking for a VB.NET version.
#imports System
#imports System.IO
#imports Newtonsoft.Json
Public Shared Function JsonPrettify(ByVal json As String) As String
Using stringReader = New StringReader(json)
Using stringWriter = New StringWriter()
Dim jsonReader = New JsonTextReader(stringReader)
Dim jsonWriter = New JsonTextWriter(stringWriter) With {
.Formatting = Formatting.Indented
}
jsonWriter.WriteToken(jsonReader)
Return stringWriter.ToString()
End Using
End Using
End Function
.NET 5 has built in classes for handling JSON parsing, serialization, deserialization under System.Text.Json namespace. Below is an example of a serializer which converts a .NET object to a JSON string,
using System.Text.Json;
using System.Text.Json.Serialization;
private string ConvertJsonString(object obj)
{
JsonSerializerOptions options = new JsonSerializerOptions();
options.WriteIndented = true; //Pretty print using indent, white space, new line, etc.
options.NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals; //Allow NANs
string jsonString = JsonSerializer.Serialize(obj, options);
return jsonString;
}
Below code works for me:
JsonConvert.SerializeObject(JToken.Parse(yourobj.ToString()))
For UTF8 encoded JSON file using .NET Core 3.1, I was finally able to use JsonDocument based upon this information from Microsoft: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-how-to#utf8jsonreader-utf8jsonwriter-and-jsondocument
string allLinesAsOneString = string.Empty;
string [] lines = File.ReadAllLines(filename, Encoding.UTF8);
foreach(var line in lines)
allLinesAsOneString += line;
JsonDocument jd = JsonDocument.Parse(Encoding.UTF8.GetBytes(allLinesAsOneString));
var writer = new Utf8JsonWriter(Console.OpenStandardOutput(), new JsonWriterOptions
{
Indented = true
});
JsonElement root = jd.RootElement;
if( root.ValueKind == JsonValueKind.Object )
{
writer.WriteStartObject();
}
foreach (var jp in root.EnumerateObject())
jp.WriteTo(writer);
writer.WriteEndObject();
writer.Flush();