i have a strange problem with the json.net serializer. Here is the code that serializers. I think there is nothing wrong with it:
var info = new Info("Peter", 25);
var filePath = Path.Combine(Application.dataPath, "test.xml");
FileStream stream = new FileStream(Path.Combine(Application.dataPath, "test.xml"), FileMode.Open);
var writer = new BsonWriter(stream);
var serializer = new JsonSerializer();
serializer.Serialize(writer, info);
stream.Close();
and the Info class:
public class Info
{
public string name;
public int age;
public Info(string name, int age)
{
this.name = name;
this.age = age;
}
}
when this serializes some strange charactes come out instead of the json valid brackets. It's kind of unreadable for a lot of data:
also the age doesn't seem to be serialized. Is this a problem with the used characterset or something? For me its very handy if i can check wheather everything serializes correctly by looking into the files. Also setting the indent setting for the serializer doesn't make a different. How can i fix this?
I think your problem is that you are using BsonWriter and expecting a readable text file, try using a TextWriter instead:
var info = new Info("Peter", 25);
var filePath = Path.Combine(Application.dataPath, "test.xml");
TextWriter writer = File.CreateText(Path.Combine(Application.dataPath, "test.xml"));
var serializer = new JsonSerializer();
serializer.Serialize(writer, info);
writer.Close();
Related
I need a JSON serializer/deserializer that comes with .NET. I cannot use Newtonsoft Json.NET.
As far as I know, that leaves me with JavaScriptSerializer and DataContractJsonSerializer. JavaScriptSerializer didn't work properly, because it insists on some silly format for datetimes, which loses the UTC offset after being deserialized, nevermind that.
I am using DataContractJsonSerializer, and the test method below shows what is wrong.
I am specififying custom date format (ISO) for both serialization and deserialization, and the string looks OK. Additionally, it is readable by the Json.NET correctly.
How can I efficiently and generically workaround this issue, without doing any regexes and manual conversions?
[Test]
public void SerializerFailure()
{
TestObject testObject = new TestObject() {Dict = new Dictionary<string, object>() {{"DateTest", DateTime.UtcNow}, {"DecimalTest", 66.6M}}};
Assert.IsInstanceOf<DateTime>(testObject.Dict["DateTest"]);
string serialized = this.Serialize(testObject);
//output is OK...
//{"Dict":{"DateTest":"2019-01-07T23:16:59.5142225Z","DecimalTest":66.6}}
TestObject deserialized = this.Deserialize<TestObject>(serialized);
Assert.IsInstanceOf<string>(deserialized.Dict["DateTest"]);
TestObject newtonDeserialized = JsonConvert.DeserializeObject<TestObject>(serialized);
testObject.ShouldBeEquivalentTo(newtonDeserialized); //passes OK
testObject.ShouldBeEquivalentTo(deserialized); //Fails
//ERROR: Expected member Dict[DateTest] to be
// "2019-01-07T23:27:23.0758967Z" with a length of 28, but
// "07.01.2019 23:27:23" has a length of 19.
// Expected member Dict[DateTest] to be
// "2019-01-07T23:27:23.0758967Z", but
// "07.01.2019 23:27:23" differs near "07."(index 0).
}
Serialization:
public string Serialize(object objectToPost)
{
using (MemoryStream stream = new System.IO.MemoryStream())
{
var settings = new DataContractJsonSerializerSettings() { DateTimeFormat = new DateTimeFormat("O"), UseSimpleDictionaryFormat = true };
DataContractJsonSerializer serializer
= new DataContractJsonSerializer(objectToPost.GetType(), settings);
serializer.WriteObject(stream, objectToPost);
stream.Flush();
stream.Seek(0, SeekOrigin.Begin);
using (StreamReader reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
}
Deserialization
public T Deserialize<T>(string stringContent)
{
try
{
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(stringContent)))
{
var settings = new DataContractJsonSerializerSettings() { DateTimeFormat = new DateTimeFormat("O"), UseSimpleDictionaryFormat = true };
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T), settings);
return (T)serializer.ReadObject(ms);
}
}
catch (Exception ex)
{
throw new InvalidOperationException($"Error while deserializing string as {typeof(T).Name}", ex);
}
}
I have a custom type UserSettingConfig I want to save in my database, I want to save it as pure XML as the type might be changed later and migrating pure xml is easier than a binary objet.
public class Serialize
{
private readonly DataContractSerializer _serializer;
public Serialize()
{
_serializer = new DataContractSerializer(typeof(UserSettingConfig));
}
public string SerializeObject(UserSettingConfig userSettingConfig)
{
using (var memoryStream = new MemoryStream())
{
_serializer.WriteObject(memoryStream, userSettingConfig);
string userSettingXml = memoryStream.ToString();
memoryStream.Close();
return userSettingXml;
}
}
public UserSettingConfig DeSerializeObject(string userSettingXml)
{
UserSettingConfig userSettingConfig;
using (var stream = new MemoryStream(userSettingXml))
{
stream.Position = 0;
userSettingConfig = (UserSettingConfig)_serializer.ReadObject(stream);
}
return userSettingConfig;
}
}
This dont work as the Memory Stream want a byte array or int
I want my Serialize to return a string (I can save as varchar(MAX) in my database)
DataContractSerializer.WriteObject has an overload that takes an XmlWriter. You can construct one of those that writes the XML to a StringBuilder:
private static string SerializeToString(object objectToSerialize)
{
var serializer = new DataContractSerializer(objectToSerialize.GetType());
var output = new StringBuilder();
var xmlWriter = XmlWriter.Create(output);
serializer.WriteObject(xmlWriter, objectToSerialize);
xmlWriter.Close();
return output.ToString();
}
You may also consider serializing to JSON instead of XML, using the excellent JSON.NET library which can serialize even the most complex objects easily. JSON is very compact and is still readable.
To serialize:
string json = Newtonsoft.Json.JavaScriptConvert.SerializeObject(anySerializableObject);
To deserialize:
MyClass instance = (MyClass) Newtonsoft.Json.JavaScriptConvert.DeserializeObject(json, typeof(MyClass));
If you need xml without xml declaration, you should use XmlWriterSettings. For instance when you need xml string for node but not entire xml document.
private static string SerializeToString(object objectToSerialize)
{
var serializer = new DataContractSerializer(objectToSerialize.GetType());
var output = new StringBuilder();
var xmlWriter = XmlWriter.Create(output, new XmlWriterSettings() { OmitXmlDeclaration = true});
serializer.WriteObject(xmlWriter, objectToSerialize);
xmlWriter.Close();
return output.ToString();
}
EDIT:
Doing too much.... this works for me with national chars
var xs = new XmlSerializer(typeof(ToDoItem));
var stringWriter = new StringWriter();
xs.Serialize(stringWriter, item);
var test = XDocument.Parse(stringWriter.ToString());
...where The item is the object containing strings with national chars
/EDIT
I did a project with serialization of some objects.
I copied some code from examples on this site and everything worked great, till I changed framework ASP.NET from 3.5 til 4.0... (and changed ISS7 .net setting from v2.0 to v4.0)
I am 99% sure this is the cause of the following error:
Before this change something like this:
var test = XDocument.Parse(SerializeObject("æøåAØÅ", typeof(string)));
test.Save(HttpContext.Current.Server.MapPath("test.xml"));
Would save the xml with the exact chars used.
Now it saves this:
���A��
I would like: Information on settings I might have to make in IIS7
OR
A comment on how to change the serializing methods to handle the national chars better.
This is the serialization code used.
private static String UTF8ByteArrayToString(Byte[] characters)
{
var encoding = new UTF8Encoding();
String constructedString = encoding.GetString(characters);
return (constructedString);
}
public static String SerializeObject(Object pObject, Type type)
{
try
{
String XmlizedString = null;
var memoryStream = new MemoryStream();
var xs = new XmlSerializer(type);
var xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.ASCII);
xs.Serialize(xmlTextWriter, pObject);
memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());
return XmlizedString.Trim();
}
catch (Exception e)
{
//Console.WriteLine(e);
return null;
}
}
You save a text as using ASCII and then decode it using UTF-8 and expect that it will work? It won't. This code could never work properly, regardless of any updates or settings.
There is no need to write the XML to a MemoryStream and then decode that. Just use StringWriter:
var xs = new XmlSerializer(type);
var stringWriter = new StringWriter();
xs.Serialize(stringWriter, pObject);
return stringWriter.ToString();
I am sending a request to a web service which requires a string containing XML, of which I have been giving an XSD.
I've ran xsd.exe and created a class based on this but am unsure of the best way to create the xml string to send, for example a stream, XMLDocument or some form of serialization.
UPDATE
I found this here
public static string XmlSerialize(object o)
{
using (var stringWriter = new StringWriter())
{
var settings = new XmlWriterSettings
{
Encoding = Encoding.GetEncoding(1252),
OmitXmlDeclaration = true
};
using (var writer = XmlWriter.Create(stringWriter, settings))
{
var xmlSerializer = new XmlSerializer(o.GetType());
xmlSerializer.Serialize(writer, o);
}
return stringWriter.ToString();
}
}
which lets me control the tag attribute.
What I am doing on several occasions is creating a class/struct to hold the data on the client-side program and serializing the data as a string. Then I make the web request and send it that XML string. Here is the code I use to serialize an object to XML:
public static string SerializeToString(object o)
{
string serialized = "";
System.Text.StringBuilder sb = new System.Text.StringBuilder();
//Serialize to memory stream
System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(o.GetType());
System.IO.TextWriter w = new System.IO.StringWriter(sb);
ser.Serialize(w, o);
w.Close();
//Read to string
serialized = sb.ToString();
return serialized;
}
As long as all the contents of the object are serializable it will serialize any object.
Use Xstream framework to generate an xml string. Hope this helps!
Here's what I have done before:
private static string CreateXMLString(object o)
{
XmlSerializer serializer = new XmlSerializer(typeof(object));
var stringBuilder = new StringBuilder();
using (var writer = XmlWriter.Create(stringBuilder))
{
serializer.Serialize(writer, o);
}
return stringBuilder.ToString();
}
Problem
By leveraging some samples I found online here, I've written some XML serialization methods.
Method1: Serialize an Object and return: (a) the type, (b) the xml string
Method2: Takes (a) and (b) above and gives you back the Object.
I noticed that the xml string from the Method1 contains a leading '?'. This seems to be fine when using Method2 to reconstruct the Object.
But when doing some testing in the application, sometimes we got leading '???' instead. This caused the Method2 to throw an exception while trying to reconstruct the Object.
The 'Object' in this case was just a simple int.
System.InvalidOperationException was unhandled
Message="There is an error in XML document (1, 1)."
Source="System.Xml"
StackTrace:
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
at System.Xml.Serialization.XmlSerializer.Deserialize(Stream stream)
at XMLSerialization.Program.DeserializeXmlStringToObject(String xmlString, String objectType) in C:\Documents and Settings\...Projects\XMLSerialization\Program.cs:line 96
at XMLSerialization.Program.Main(String[] args) in C:\Documents and Settings\...Projects\XMLSerialization\Program.cs:line 49
Would anyone be able to shed some light on what might be causing this?
Sample Code
Here's sample code from the mini-tester I wrote while coding this up which runs as a VS console app. It'll show you the XML string. You can also uncomment the regions to append the extra leading '??' to reproduce the exception.
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace XMLSerialization
{
class Program
{
static void Main(string[] args)
{
// deserialize to string
#region int
object inObj = 5;
#endregion
#region string
//object inObj = "Testing123";
#endregion
#region list
//List inObj = new List();
//inObj.Add("0:25");
//inObj.Add("1:26");
#endregion
string[] stringArray = SerializeObjectToXmlString(inObj);
#region include leading ???
//int indexOfBracket = stringArray[0].IndexOf('<');
//stringArray[0] = "??" + stringArray[0];
#endregion
#region strip out leading ???
//int indexOfBracket = stringArray[0].IndexOf('<');
//string trimmedString = stringArray[0].Substring(indexOfBracket);
//stringArray[0] = trimmedString;
#endregion
Console.WriteLine("Input");
Console.WriteLine("-----");
Console.WriteLine("Object Type: " + stringArray[1]);
Console.WriteLine();
Console.WriteLine("XML String: " + Environment.NewLine + stringArray[0]);
Console.WriteLine(String.Empty);
// serialize back to object
object outObj = DeserializeXmlStringToObject(stringArray[0], stringArray[1]);
Console.WriteLine("Output");
Console.WriteLine("------");
#region int
Console.WriteLine("Object: " + (int)outObj);
#endregion
#region string
//Console.WriteLine("Object: " + (string)outObj);
#endregion
#region list
//string[] tempArray;
//List list = (List)outObj;
//foreach (string pair in list)
//{
// tempArray = pair.Split(':');
// Console.WriteLine(String.Format("Key:{0} Value:{1}", tempArray[0], tempArray[1]));
//}
#endregion
Console.Read();
}
private static string[] SerializeObjectToXmlString(object obj)
{
XmlTextWriter writer = new XmlTextWriter(new MemoryStream(), Encoding.UTF8);
writer.Formatting = Formatting.Indented;
XmlSerializer serializer = new XmlSerializer(obj.GetType());
serializer.Serialize(writer, obj);
MemoryStream stream = (MemoryStream)writer.BaseStream;
string xmlString = UTF8ByteArrayToString(stream.ToArray());
string objectType = obj.GetType().FullName;
return new string[]{xmlString, objectType};
}
private static object DeserializeXmlStringToObject(string xmlString, string objectType)
{
MemoryStream stream = new MemoryStream(StringToUTF8ByteArray(xmlString));
XmlSerializer serializer = new XmlSerializer(Type.GetType(objectType));
object obj = serializer.Deserialize(stream);
return obj;
}
private static string UTF8ByteArrayToString(Byte[] characters)
{
UTF8Encoding encoding = new UTF8Encoding();
return encoding.GetString(characters);
}
private static byte[] StringToUTF8ByteArray(String pXmlString)
{
UTF8Encoding encoding = new UTF8Encoding();
return encoding.GetBytes(pXmlString);
}
}
}
When I've come across this before, it usually had to do with encoding. I'd try specifying the encoding when you serialize your object. Try using the following code. Also, is there any specific reason why you need to return a string[] array? I've changed your methods to use generics so you don't have to specify a type.
private static string SerializeObjectToXmlString<T>(T obj)
{
XmlSerializer xmls = new XmlSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream())
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
settings.Indent = true;
settings.IndentChars = "\t";
settings.NewLineChars = Environment.NewLine;
settings.ConformanceLevel = ConformanceLevel.Document;
using (XmlWriter writer = XmlTextWriter.Create(ms, settings))
{
xmls.Serialize(writer, obj);
}
string xml = Encoding.UTF8.GetString(ms.ToArray());
return xml;
}
}
private static T DeserializeXmlStringToObject <T>(string xmlString)
{
XmlSerializer xmls = new XmlSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xmlString)))
{
return (T)xmls.Deserialize(ms);
}
}
If you still have problems, try using Encoding.ASCII in your code anywhere you see Encoding.UTF8, unless you have a specific reason for using UTF8. I'm not sure of the cause, but I've seen UTF8 encoding cause this exact problem in certain cases when serializing.
This is BOM symbol. You can either remove it
if (xmlString.Length > 0 && xmlString[0] != '<')
{
xmlString = xmlString.Substring(1, xmlString.Length - 1);
}
Or use UTF32 to serialize
using (StringWriter writer = new StringWriter(CultureInfo.InvariantCulture))
{
serializer.Serialize(writer, instance);
result = writer.ToString();
}
And deserialize
object result;
using (StringReader reader = new StringReader(instance))
{
result = serializer.Deserialize(reader);
}
If you are using this code only inside .Net applications using UTF32 won't create problems as it's the default encoding for everything inside .Net