XMLSerializer serialising date error : Is not a valid AllXsd - c#

Im using the XmlSerializer to serialise objects which contain a datetime property.
This serialises fine with the following an example of the results produced:
<GuestUserLinkItemActivity>
<ActivityDateTime>2013-03-06T00:00:00+00:00</ActivityDateTime>
<ActivityMessage>Invitation email sent to guest.</ActivityMessage>
</GuestUserLinkItemActivity>
But then when I try and deserialise, again using the XmlSerializer, this I get the following error
The string '2013-03-06T00:00:00 00:00' is not a valid AllXsd value. xmlserializer Deserialize
There are a couple of posts I have found with similar issues but non provide a solution to this.
XmlSerializer: The string '' is not a valid AllXsd value
The string '3/18/09 10:16 PM' is not a valid AllXsd value
It most likely to do with the date being stored in format not expected and from one of the articles not in the format expected by the xml specification. so I expect if I manually amend the date stored I could get it to deserialise it properly.
How can I get the dates stored properly using the XmlSerializer.
See bits of copy and pasted code below:
public class GuestUserLinkItemActivity
{
public DateTime ActivityDateTime { get; set; }
public string ActivityMessage { get; set; }
}
Serializer class:
public static class Serializer
{
public static T DeSerialise<T>(string contentsToDesrialise)
{
if (string.IsNullOrEmpty(contentsToDesrialise))
return default(T);
var xmlSer = new XmlSerializer(typeof(T));
var stream = new MemoryStream();
var sw = new StreamWriter(stream);
sw.Write(contentsToDesrialise);
sw.Flush();
stream.Position = 0;
var obj = (T)xmlSer.Deserialize(stream);
sw.Close();
stream.Close();
return obj;
}
public static string Serialise<T>(T obectToSerialise)
{
var ms = new MemoryStream();
var sr = new XmlSerializer(typeof(T));
sr.Serialize(ms, obectToSerialise);
ms.Position = 0;
var sread = new StreamReader(ms);
var serialisedObjectString = sread.ReadToEnd();
sread.Close();
ms.Close();
return serialisedObjectString;
}
}
Usage:
var guestHistoryList = new List<GuestUserLinkItemActivity>();
guestHistoryList.Add(new GuestUserLinkItemActivity(){
ActivityDateTime = DateTime.Now,
ActivityMessage = "Invitation email sent to guest."}
);
var serialisedArray = Serializer.Serialise<GuestUserLinkItemActivity[]>(guestHistoryList.ToArray());
var deserialisedObject = Serializer.DeSerialise<GuestUserLinkItemActivity[]>(serialisedArray);

Instead of trying to serialize/deserialize an array, try with List<GuestUserLinkItemActivity> - it worked for me:
var serialisedArray = Serializer.Serialise<List<GuestUserLinkItemActivity>>(guestHistoryList);
var deserialisedObject1 = Serializer.DeSerialise<List<GuestUserLinkItemActivity>>(serialisedArray);

Related

DataContractJsonSerializer stringifies DateTime values inside dictionaries during deserialization

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);
}
}

Json.Net serializes with strange charactes instead of brackets?

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();

Convert XDocument to byte array (and byte array to XDocument)

I've taken over a system that stores large XML documents in SQL Server in binary format.
Currently the data is saved by converting it to a string, then converting that string to a byte array. But recently with some large XML documents I'm getting out memory exceptions when attempting to convert to a string, so I want to bypass this process and go straight from the XDocument to a byte array.
The Entity Framework class holding the XML has been extended so that the binary data is accessible as a string like this:
partial class XmlData
{
public string XmlString { get { return Encoding.UTF8.GetString(XmlBinary); } set { XmlBinary = Encoding.UTF8.GetBytes(value); } }
}
I want to further extend the class to look something like this:
partial class XmlData
{
public string XmlString{ get { return Encoding.UTF8.GetString(XmlBinary); } set { XmlBinary = Encoding.UTF8.GetBytes(value); } }
public XDocument XDoc
{
get
{
// Convert XmlBinary to XDocument
}
set
{
// Convert XDocument to XmlBinary
}
}
}
I think I've nearly figured out the conversion, but when I use the partial classes XmlString method to get the XML back from the DB, the XML has always been cut off near the end, always at a different character count:
var memoryStream = new MemoryStream();
var xmlWriter = XmlWriter.Create(memoryStream);
myXDocument.WriteTo(xmlWriter);
XmlData.XmlBinary = memoryStream.ToArray();
SOLUTION
Here's the basic conversion:
var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Encoding = Encoding.UTF8 };
using (var memoryStream = new MemoryStream())
using (var xmlWriter = XmlWriter.Create(memoryStream, settings))
{
myXDocument.WriteTo(xmlWriter);
xmlWriter.Flush();
XmlData.XmlBinary = memoryStream.ToArray();
}
But for some reason in this process, some weird non ascii characters get added to the XML so using my previous XmlString method would load those weird characters and XDocument.Parse() would break, so my new partial class looks like this:
partial class XmlData
{
public string XmlString
{
get
{
var xml = Encoding.UTF8.GetString(XmlBinary);
xml = Regex.Replace(xml, #"[^\u0000-\u007F]", string.Empty); // Removes non ascii characters
return xml;
}
set
{
value = Regex.Replace(value, #"[^\u0000-\u007F]", string.Empty); // Removes non ascii characters
XmlBinary = Encoding.UTF8.GetBytes(value);
}
}
public XDocument XDoc
{
get
{
using (var memoryStream = new MemoryStream(XmlBinary))
using (var xmlReader = XmlReader.Create(memoryStream))
{
var xml = XDocument.Load(xmlReader);
return xml;
}
}
set
{
var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Encoding = Encoding.UTF8 };
using (var memoryStream = new MemoryStream())
using (var xmlWriter = XmlWriter.Create(memoryStream, settings))
{
value.WriteTo(xmlWriter);
xmlWriter.Flush();
XmlBinary = memoryStream.ToArray();
}
}
}
}
That sounds like buffer of one of streams / writers was not flushed during read or write - use using (...) for autoclose, flush and dispose, and also check that in all places where you finished read / write you've done .Flush()

Save datacontract serialized object as string to save in sql db

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();
}

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);
}
}

Categories

Resources