Newtonsoft.Json
Newtonsoft.Json copied to clipboard
How to use Newtonsoft.Json in place of BinaryFormatter in C# .Net?
We have legacy code, We learned that there are some vulnerabilities using BinaryFormatter. So I am trying to use NewtonSoft.Json. My project is already using NewtonSoft.Json package.
I have tried the below code but it gives an exception on the line var deserializedStream = serializer.Deserialize(jsonTextReader);when running.
Unexpected character encountered while parsing value: . Path '', line 1, position 1.
My new Code:
public void LoadFromDisk()
{
if (!File.Exists(BINARY_FILENAME)) return;
var serializer = new JsonSerializer();
using (var stream = File.Open(BINARY_FILENAME, FileMode.Open, FileAccess.Read))
{
using (var sr = new StreamReader(stream))
{
using (var jsonTextReader = new JsonTextReader(sr))
{
var deserializedStream = serializer.Deserialize(jsonTextReader);
_jobsAck = deserializedStream as ConcurrentDictionary<string, DateTime>;
if (_jobsAck == null)
{
_jobsAck = new ConcurrentDictionary<string, DateTime>();
if (!(deserializedStream is Dictionary<string, DateTime> ackDict)) return;
foreach (var pair in ackDict)
{
_jobsAck.TryAdd(pair.Key, pair.Value);
}
}
}
}
}
}
Old Code:
public void LoadFromDisk()
{
if (!File.Exists(BINARY_FILENAME)) return;
var binaryFormatter = new BinaryFormatter();
using (var stream = File.Open(BINARY_FILENAME, FileMode.Open, FileAccess.Read))
{
var deserializedStream = binaryFormatter.Deserialize(stream);
_jobsAck = deserializedStream as ConcurrentDictionary<string, DateTime>;
if (_jobsAck == null)
{
_jobsAck = new ConcurrentDictionary<string, DateTime>();
if (!(deserializedStream is Dictionary<string, DateTime> ackDict)) return;
foreach (var pair in ackDict)
{
_jobsAck.TryAdd(pair.Key, pair.Value);
}
}
}
```}
**Target framework**: 4.7.2 (I cannot upgrade .net framework due to some constraints)
**NewtonSoft version:** 12.0.2
At a guess from the error message, it looks like the BINARY_FILENAME
file is still written with BinaryFormatter
. Make sure you delete the file, and replace your SaveToDisk
method first so that the written data is serialized in Json format.
Unless you use a custom convention of some sort, I don't think it can deserialize directly to a ConcurrentDictionary
.
I think your code could be something like:
using Newtonsoft.Json;
using System.Collections.Concurrent;
internal class Program
{
private ConcurrentDictionary<string, DateTime> _jobsAck = new();
private const string JSON_FILENAME = "JobsAck.json";
public ConcurrentDictionary<string, DateTime> JobsAck { get => _jobsAck; set => _jobsAck = value; }
public void LoadFromDisk()
{
if (!File.Exists(JSON_FILENAME)) return;
var serializer = new JsonSerializer();
using (var stream = File.Open(JSON_FILENAME, FileMode.Open, FileAccess.Read))
{
using (var sr = new StreamReader(stream))
{
using (var jsonTextReader = new JsonTextReader(sr))
{
var ackDict = serializer.Deserialize<Dictionary<string, DateTime>>(jsonTextReader);
if (ackDict != null)
{
_jobsAck = new ConcurrentDictionary<string, DateTime>();
foreach (var pair in ackDict)
{
_jobsAck.TryAdd(pair.Key, pair.Value);
}
}
}
}
}
}
public void SaveToDisk()
{
var serializer = new JsonSerializer();
using (var stream = File.Open(JSON_FILENAME, FileMode.Create, FileAccess.Write))
{
using (var sw = new StreamWriter(stream))
{
using (var jsonTextWriter = new JsonTextWriter(sw)
{
Formatting = Formatting.Indented // Not needed, and makes the file a little larger, but is much more readable.
})
{
serializer.Serialize(jsonTextWriter, _jobsAck);
}
}
}
}
static void Main(string[] args)
{
var prog = new Program();
prog.LoadFromDisk();
prog.JobsAck.TryAdd(Guid.NewGuid().ToString(), DateTime.UtcNow);
prog.SaveToDisk();
}
}
Hope this helps.