Why is Newtonsoft "ReferenceLoopHandling.Ignore" not ignoring? - c#

I have a DeepClone function using Newtonsoft:
public static T DeepClone2<T>(this T obj)
{
var jsonSettings = new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
TypeNameHandling = TypeNameHandling.All
};
var stringBuilder = new StringBuilder();
var stringWriter = new StringWriter(stringBuilder);
using (JsonWriter writer = new JsonTextWriter(stringWriter))
{
writer.Formatting = Formatting.None;
var serializer = JsonSerializer.Create(jsonSettings);
serializer.Serialize(writer, obj);
writer.Flush();
}
string objSerialized = stringBuilder.ToString();
T clonedObj = JsonConvert.DeserializeObject<T>(objSerialized, jsonSettings);
return clonedObj;
}
This function is exploding the stack memory when the object has a loop.
However, if I configure the ReferenceLoopHandling to Error, then it gives an error.
Why isn't the loop ignored?

Related

XML Files and receiving them without headers

The company receives a form of XML files and stores them on an S3 bucket, the information is then shown on a customers website.
Issue I am having is they have onboarded a new customer with a new feed. The customers feed which they are now sending me are correct, Although their XML files are missing the declaration at the top.
Example of Declaration missing
<?xml version="1.0" encoding="UTF-8"?>
This is stopping the feed from processing and displaying on the website.
If I manually add the Declaration and re upload it works.
Now the customer is saying they have never had the headers and it works for other 3rd party companies.
Is there a way to add the header once receiving the files, the feed processor & FTP server are in c#, dotnet3.1
public static T Deserialize<T>(XmlReader reader)
{
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty, new XmlQualifiedName("xs", "http://www.w3.org/2001/XMLSchema") });
object retVal = null;
XmlSerializer serializer = new XmlSerializer(typeof(T));
var settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.ConformanceLevel = ConformanceLevel.Document;
settings.DtdProcessing = DtdProcessing.Parse;
// using (StringReader stringReader = new StringReader(objectXml))
// using (var xmlReader = XmlReader.Create(stringReader, settings))
{
retVal = serializer.Deserialize(reader);
return (T)retVal;
}
}
public static T Deserialize<T>(XDocument xdoc)
{
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty, new XmlQualifiedName("xs", "http://www.w3.org/2001/XMLSchema") });
object retVal = null;
XmlSerializer serializer = new XmlSerializer(typeof(T));
var settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.ConformanceLevel = ConformanceLevel.Document;
settings.DtdProcessing = DtdProcessing.Parse;
using (StringReader stringReader = new StringReader(xdoc.ToString()))
using (var xmlReader = XmlReader.Create(stringReader, settings))
{
retVal = serializer.Deserialize(xmlReader);
return (T)retVal;
}
}
public static T Deserialize<T>(string objectXml)
{
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty, new XmlQualifiedName("xs", "http://www.w3.org/2001/XMLSchema") });
object retVal = null;
XmlSerializer serializer = new XmlSerializer(typeof(T));
var settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.ConformanceLevel = ConformanceLevel.Document;
settings.DtdProcessing = DtdProcessing.Parse;
using (StringReader stringReader = new StringReader(objectXml))
using (var xmlReader = XmlReader.Create(stringReader, settings))
{
retVal = serializer.Deserialize(xmlReader);
return (T)retVal;
}
}
// public static T Deserialize<T>(string objectXml, string xmlNamespace)
// {
// var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty, new XmlQualifiedName("xs", xmlNamespace) });
// object retVal = null;
// XmlSerializer serializer = new XmlSerializer(typeof(T));
// var settings = new XmlReaderSettings();
// settings.IgnoreComments = true;
// settings.ConformanceLevel = ConformanceLevel.Document;
// settings.DtdProcessing = DtdProcessing.Parse;
// using (StringReader stringReader = new StringReader(objectXml))
// using (var xmlReader = XmlReader.Create(stringReader, settings))
// {
// retVal = serializer.Deserialize(xmlReader);
// return (T)retVal;
// }
// }
public static T Deserialize<T>(Stream xmlStream)
{
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty, new XmlQualifiedName("xs", "http://www.w3.org/2001/XMLSchema") });
object retVal = null;
XmlSerializer serializer = new XmlSerializer(typeof(T));
var settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.ConformanceLevel = ConformanceLevel.Document;
settings.DtdProcessing = DtdProcessing.Ignore;
using (var xmlReader = XmlReader.Create(xmlStream, settings))
{
retVal = serializer.Deserialize(xmlReader);
return (T)retVal;
}
}
}
}
public static class XmlUtil
{
public static string SerializeToString<T>(T value)
{
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var serializer = new XmlSerializer(value.GetType());
var settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = false;
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, settings))
{
// This adds our DocType
writer.WriteDocType("propertyList", null, "http://reaxml.realestate.com.au/propertyList.dtd", null);
serializer.Serialize(writer, value, emptyNamespaces);
return stream.ToString();
}
}
public static string SerializeToStringUTF8<T>(T value)
{
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var serializer = new XmlSerializer(value.GetType());
var settings = new XmlWriterSettings();
settings.Indent = true;
settings.Encoding = Encoding.UTF8;
settings.OmitXmlDeclaration = false;
using (var stream = new StringWriterWithEncoding(Encoding.UTF8))
using (var writer = XmlWriter.Create(stream, settings))
{
// This adds our DocType
writer.WriteDocType("propertyList", null, "http://reaxml.realestate.com.au/propertyList.dtd", null);
serializer.Serialize(writer, value, emptyNamespaces);
return stream.ToString();
}
}

JsonSerializer size limited to 7168 chars/bytes?

Consider this sample code:
var ms = new MemoryStream();
using (StreamWriter sw = new StreamWriter(ms))
using (JsonWriter writer = new JsonTextWriter(sw))
{
this.GetSerializer().Serialize(writer, data, typeof(T));
// convert stream to string
ms.Position = 0;
var reader = new StreamReader(ms);
var textToSend = reader.ReadToEnd();
}
Serializer obtained from this method:
private JsonSerializer GetSerializer()
{
var serializer = new JsonSerializer
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
serializer.Converters.Add(new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd\\THH:mm:ss.fffZ" });
return serializer;
}
When I serialize 'data' it produces memory stream with 7168 bytes and when I convert to string I see how message being truncated. Searched but can't find what might be causing this limit?

Converting code to use JSON.net instead of System.Runtime.Serialization.DataContractSerializer

How do I do the equivalent in JSON.net?
public SerializedResults SerializeResults(Type queryType, IEnumerable entities)
{
var results = SerializeDynamicType(queryType);
var objList = AnonymousFns.DeconstructMany(entities, false, queryType).ToList();
var ms = new MemoryStream();
var type = objList.GetType();
var serializer = new DataContractSerializer(type);
using (ms)
{
using (GZipStream compress = new GZipStream(ms, CompressionMode.Compress, CompressionLevel.BestCompression))
{
serializer.WriteObject(compress, objList);
}
}
results.ByteArray = ms.ToArray();
return results;
}
I am confused with this line in particular:
var serializer = new DataContractSerializer(type);
How do you do that in JSON.NET??
THANKS :-)
With JSON.NET, you don't need the type when serializing. I'm assuming that it works out the type you are passing in on its own.
So, you can get rid of this completely:
var type = objList.GetType();
var serializer = new DataContractSerializer(type);
And change this:
serializer.WriteObject(compress, objList);
To:
var json = JsonConvert.SerializeObject(objList);
Here are the JSON.Net docs for JsonConvert.
I believe you can use the BsonWriter to write to a stream. I'm not sure it will give you the exact same binary format you had before, but in concept it is the same.
public SerializedResults SerializeResults(Type queryType, IEnumerable entities)
{
var results = SerializeDynamicType(queryType);
var objList = AnonymousFns.DeconstructMany(entities, false, queryType).ToList();
var ms = new MemoryStream();
using (ms)
{
using (GZipStream compress = new GZipStream(ms, CompressionMode.Compress, CompressionLevel.BestCompression))
{
using( BsonWriter writer = new BsonWriter(compress))
{
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(writer, objList);
}
}
}
results.ByteArray = ms.ToArray();
return results;
}

Deserialize from string instead TextReader

I want to change my code from:
string path = #"c:\Directory\test.xml";
XmlSerializer s = new XmlSerializer(typeof(Car));
TextReader r = new StreamReader(path);
Car car = (Car)s.Deserialize(r);
r.Close();
into code that would convert an XML to a string, and then convert string to the object Car.
Is this possible?
public static string XmlSerializeToString(this object objectInstance)
{
var serializer = new XmlSerializer(objectInstance.GetType());
var sb = new StringBuilder();
using (TextWriter writer = new StringWriter(sb))
{
serializer.Serialize(writer, objectInstance);
}
return sb.ToString();
}
public static T XmlDeserializeFromString<T>(this string objectData)
{
return (T)XmlDeserializeFromString(objectData, typeof(T));
}
public static object XmlDeserializeFromString(this string objectData, Type type)
{
var serializer = new XmlSerializer(type);
object result;
using (TextReader reader = new StringReader(objectData))
{
result = serializer.Deserialize(reader);
}
return result;
}
To use it:
//Make XML
var settings = new ObjectCustomerSettings();
var xmlString = settings.XmlSerializeToString();
//Make Object
var settings = xmlString.XmlDeserializeFromString<ObjectCustomerSettings>();
If you have the XML stored inside a string variable you could use a StringReader:
var xml = #"<car/>";
var serializer = new XmlSerializer(typeof(Car));
using (var reader = new StringReader(xml))
{
var car = (Car)serializer.Deserialize(reader);
}
1-liner, takes a XML string text and YourType as the expected object type. not very different from other answers, just compressed to 1 line:
var result = (YourType)new XmlSerializer(typeof(YourType)).Deserialize(new StringReader(text));
static T DeserializeXml<T>(string sourceXML) where T : class
{
var serializer = new XmlSerializer(typeof(T));
T result = null;
using (TextReader reader = new StringReader(sourceXML))
{
result = (T) serializer.Deserialize(reader);
}
return result;
}
Shamelessly copied from
Generic deserialization of an xml string
public static T DeserializeFromXmlString<T>(string xmlString)
{
var serializer = new XmlSerializer(typeof(T));
using (TextReader reader = new StringReader(xmlString))
{
return (T) serializer.Deserialize(reader);
}
}

InvalidOperationException while SOAP serialization of complex type

I encountered a problem with SOAP serialization and it would be great to find an answer. Here's a very simplified example:
public void Test()
{
StringBuilder sb = new StringBuilder();
StringWriter writer = new StringWriter(sb);
SoapReflectionImporter importer = new SoapReflectionImporter();
XmlTypeMapping map = importer.ImportTypeMapping(typeof(A));
XmlSerializer serializer = new XmlSerializer(map);
serializer.Serialize(writer, new A());
}
[Serializable]
public class A
{
public A()
{
BB = new B();
}
public int a;
public B BB;
}
[Serializable]
public class B
{
public int A1 { get; set; }
public int A2 { get; set; }
}
If I run method Test() then I get the following exception: System.InvalidOperationException: Token StartElement in state Epilog would result in an invalid XML document.
Would appreciate any help.
Use XmlWriter instead of StringWriter and do a writer.WriteStartElement("root");
This will work:
Stream s = new MemoryStream();
XmlWriter writer = new XmlTextWriter(s, Encoding.UTF8);
SoapReflectionImporter importer = new SoapReflectionImporter();
XmlTypeMapping map = importer.ImportTypeMapping(typeof(A));
XmlSerializer serializer = new XmlSerializer(map);
writer.WriteStartElement("root");
serializer.Serialize(writer, new A());
StreamReader sr = new StreamReader(s);
string data = sr.ReadToEnd();
Just a note,
The upper example will not work if the position of the stream is not set to the start of the stream. Like so:
Stream s = new MemoryStream();
XmlWriter writer = new XmlTextWriter(s, Encoding.UTF8);
SoapReflectionImporter importer = new SoapReflectionImporter();
XmlTypeMapping map = importer.ImportTypeMapping(typeof(A));
XmlSerializer serializer = new XmlSerializer(map);
writer.WriteStartElement("root");
serializer.Serialize(writer, new A());
s.Position = 0;
StreamReader sr = new StreamReader(s);
string data = sr.ReadToEnd();

Categories

Resources