With Newtonsoft Json you can convert an object to a JObject by calling JObject.FromObject(object).
Is there a counterpart in System.Text.Json to get a JsonDocument from an object?
There is an open issue for it.
But now there is no such methods. You can try
using (JsonDocument document = JsonDocument.Parse(JsonSerializer.Serialize(object)))
{
...
}
One more issue
As of .NET 6.0 (comes with System.Text.Json 6.0.0), JsonSerializer.SerializeToDocument is available.
JsonDocument doc = JsonSerializer.SerializeToDocument(yourObject);
Related
I'm adapting a older application written in .NET Framework 4.8 to .NET 6 due to a new version of an API that it uses. There is unchanged logic that serializes and deserializes models created by the API using BinaryFormatter. However, there is a strange cross-compatibility issue as below:
Model serialized in .NET 4.8 -> Model deserialized in .NET 6.0 - Fails
Model serialized in .NET 6.0 -> Model deserialized in .NET 4.8 - Works
The exception is "System.Runtime.Serialization.SerializationException: 'Invalid BinaryFormatter stream.'" and the inner exception is "ArgumentException: Type '<my type>' is not deserializable."
Assembly names and types appear to be correct in my deserialization binder, which is the extent that I'm able to step deeper into this code. I'm moreover puzzled how, if assembly versions from my app are the culprit, that going from 6.0 to 4.8 succeeds.
My research into this issue has only come up with a few issues such as this one (https://github.com/dotnet/runtime/issues/35346) but that involve .NET Core. I understand that BinaryFormatter is deprecated and has security issues per the MS documentation, but converting everything to use JSON/XML is not really a realistic solution at this point.
Is anyone aware of issues affecting BinaryFormatter backwards compatibility in more contemporary .NET versions?
Edit: As requested here is a minimally reproducible example. I don't want to share any of my actual code or types but it appears that System.Random suffers from a similar problem as well:
// .NET Framework 4.8
FileStream fs = new FileStream("DataFile.dat", FileMode.Create);
try
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, new Random());
}
catch (SerializationException) { throw; }
finally { fs.Close(); }
FileStream fs2 = new FileStream("DataFile.dat", FileMode.Open);
try
{
BinaryFormatter formatter2 = new BinaryFormatter();
var randomObj = formatter2.Deserialize(fs2); // Succeeds
}
catch (SerializationException) { throw; }
finally { fs.Close(); }
// .NET 6.0
FileStream fs = new FileStream("DataFile.dat", FileMode.Open);
try
{
BinaryFormatter formatter = new BinaryFormatter();
var randomObj = formatter.Deserialize(fs); // Fails
}
catch (SerializationException){ throw; }
finally { fs.Close(); }
There are known risks in using BinaryFormatter for serialization and deserialization of objects - particularly across versions of framework.
Please have a look at the link which actively discourages using binary formatter for serialization/deserialization of objects using binaryformatter.
Also, .Net 5 onwards the deserialization operation on binaryformatter throws an exception of type NotSupportedException. Refer to exceptions tag on this link for more information.
An example:
If we type scoreDir in the C# Console, its content is pretty printed, i.e. the definition of the object, its length and its data.
I would like to simulate this printing with a built-in .NET method, e.g. ToString(). However, ToString() doesn't work, as showed. "Simulate" means I can generate the same printed string, but store it in a variable. Microsoft must have used some function to print such object; it's best to just re-use the function (no re-inventing the wheels).
Credits to #Hans Passant in the comment section.
In Visual Studio, after installing the Nuget package Microsoft.CodeAnalysis.CSharp.Scripting, the static function Microsoft.CodeAnalysis.CSharp.Scripting.Hosting.CSharpObjectFormatter.Instance.FormatObject() can be used to mimic the same output as C# Interactive Console.
Here is the code that works:
using System;
using System.IO;
using System.Collections.Concurrent;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var scoreDir = new ConcurrentDictionary<(int, int), (double, int)>();
scoreDir.TryAdd((1, 2), (0.9, 3));
var res = Microsoft.CodeAnalysis.CSharp.Scripting.Hosting.CSharpObjectFormatter.Instance.FormatObject(scoreDir);
Console.WriteLine(res);
}
}
}
Result:
There is no such build tool for this but you can convert it to Json. The problem with your example that is not so easy for a ConcurrentDictionary.
IMPORTANT NOTE:
This only will work for Newtonsoft and .NET 6.0 since System.Text.Json does not provide a cast for serialize to JSON ConcurrentDictionary and this also don't work for Newtonsoft in .NET Framework
How to Serialize to JSON string a ConcurrentDictionary?
Import Newtonsoft.Json from Nugget
Add using Newtonsoft.Json; to the references in the head of the file
ConcurrentDictionary<(int,int), (double,int)> scoreDir = new ConcurrentDictionary<(int,int), (double,int)>();
scoreDir.TryAdd((1,2),(0.9,3));
string jsonString = JsonConvert.SerializeObject(scoreDir);
Console.WriteLine(jsonString);
Returns:
{"(1, 2)":{"Item1":0.9,"Item2":3}}
Fiddle: https://dotnetfiddle.net/XzHHoN
Using .Net Framework 4.6.1 this works perfectly:
private DataTable GetRESTData(string pUri)
{
var json = ReadFromUri(pUri);
var obj = JsonConvert.DeserializeObject(json);
string StrContent = ((Newtonsoft.Json.Linq.JObject)obj).Last.ToString();
StrContent = StrContent.Substring(9, StrContent.Length - 9);
DataTable dt = JsonConvert.DeserializeObject<DataTable>(StrContent);
return dt;
}
This also works:
DataTable dt = (DataTable)JsonConvert.DeserializeObject(StrContent.Substring(9, StrContent.Length - 9), (typeof(DataTable)));
But I can't find anything that works on CORE 2.0 Console App, I always get:
Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'System.Data.DataTable' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either chang...
If I watch the string StrContent.Substring(9, StrContent.Length - 9) as JSON or as a string, it's perfectly formatted.
I installed NewtonSoft from Nuget Package Manager.
EDIT: I'm using Visual Studio 2017. If I run this on project with Framework 4.6.1 it works perfectly, Project with CORE 2.0 shows the error I posted above.
The current stable vesion of Newtonsoft.Json library does not support serializing DataSets/DataTables as in the full .NET version.
This is because the library (version 10.0.3) targets the NETStandard 1.3, but the DataSet/DataTable support was added on Net Core 2.0.
The current beta version targets NetStandard 2.0 and does support serializing datasets, so if you update your reference to use the latest beta package Newtonsoft.Json/11.0.1-beta1 or wait until a stable version is released, you will be able to serialize/deserialize.
You can check by yourself, if you serialize the following DataTable as JSON on .NET core (Newtonsoft.Json/10.0.3):
var dt = new DataTable();
dt.Columns.Add("Column1", typeof(string));
dt.Rows.Add("value");
var json = JsonConvert.SerializeObject(dt);
You will get something like this:
{
"DataTable.RemotingVersion": {
"Major": 2,
"Minor": 0,
"Build": -1,
"Revision": -1,
"MajorRevision": -1,
"MinorRevision": -1
},
"XmlSchema": "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<xs:schema xmlns=\"\" ... </diffgr:diffgram>"
}
But if you target the current beta version (11.0.1-beta1) you get:
[
{
"Column1": "value"
}
]
There is an issue on the library about this 1409
According to NewtonSoft's documentation, this code:
string props = "{\"lot\":\"TEST\",\"mhd\":\"2016-06-17\"}";
dynamic json = JsonConvert.DeserializeObject(props);
string s = json.mhd;
should work, but I get a RunTimeBinderException when I try it. I have Micrsoft.CSharp referenced and the compile works (it is a runtime error). I am compiling against .NET 4.0, using NewtonSoft version 7.
I tried accessing as json["mhd"], which works fine.
Am I missing something?
The json object is a JObject, so to get the value you need do:
string s = (string)json["mhd"];
I try this case in Newtonsoft.Json 3.5.8 version ,I get this error.
When I upgrade Newtonsoft.Json package version to 4.5.1 it works .
I think it has bug on older version.
#Candide pointed out what was wrong with your example, but if you still want to use json.mhd syntax and have real dynamic object to work with you can do it.
Try to deserialize it using the ExpandoObjectConverter:
var converter = new ExpandoObjectConverter();
dynamic json = JsonConvert.DeserializeObject<ExpandoObject>(props, converter);
This is in the context of Web Services (client end).
I need to interface with a back-end system (Java) and it is a requirement to transmit some control characters in the and range.
I'm well aware that XML 1.0 doesn't support this, but am interested to know if the .NET 4 platform or .NET 4.5 web services framework support conversations in XML 1.1.
No, it doesn't look like XmlReader (the core of much of the XML support in .NET) supports 1.1:
using System;
using System.IO;
using System.Xml;
class Program
{
static void Main(string[] args)
{
string xml = "<?xml version=\"1.1\" ?><tag></tag>";
var reader = XmlReader.Create(new StringReader(xml));
while (reader.Read());
}
}
Output:
Unhandled Exception: System.Xml.XmlException: Version number '1.1' is invalid.
Line 1, position 16.
I've looked at XmlReaderSettings to see if anything there would help, but I don't think it does. Basically I think you're stuck for the moment :(
EDIT: Reading around XML 1.1 a bit, it looks like it's not widely deployed or recommended, so I'm not particularly surprised that it's not supported in .NET 4.5. My guess is that it never will be, given that it's not a particularly new recommendation. The most recent version is the 2nd edition which dates back to 2006. If it's not supported 7 years later, I suspect there'd have to be some significant event to make it worth supporting in the future.
I am sure this is not the best option but if you download IKVM you can use java classes in your .Net code after referencing a few assemblies (really .Net code :) )
var fXmlFile = new java.io.File(xmlfile);
var dbFactory = javax.xml.parsers.DocumentBuilderFactory.newInstance();
var dBuilder = dbFactory.newDocumentBuilder();
var doc = dBuilder.parse(fXmlFile);
var nList = doc.getElementsByTagName("controlcharacters");
var chars = nList.item(0).getTextContent().ToCharArray();
XML File:
<?xml version="1.1" ?>
<root>
<controlcharacters></controlcharacters>
</root>