I am trying to write data to a file using this code;
public async Task<bool> WriteDataAsync<T>(T data, string fileName, string folderPath)
{
try
{
var store = await GetFolder(folderPath);
using (MemoryStream sessionData = new MemoryStream())
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
serializer.WriteObject(sessionData, data);
StorageFile sessionFile = await store.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
using (Stream fileStream = await sessionFile.OpenStreamForWriteAsync())
{
sessionData.Seek(0, SeekOrigin.Begin);
await sessionData.CopyToAsync(fileStream);
await fileStream.FlushAsync();
}
}
}
For a long time it worked OK, but then I got this exception;
Type 'Microsoft.Practices.Prism.PubSubEvents.EventAggregator' with data contract name 'EventAggregator:http://schemas.datacontract.org/2004/07/Microsoft.Practices.Prism.PubSubEvents' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.
So I looked into the DataContractResolver and I found this page in MSDN;
https://msdn.microsoft.com/en-us/library/ee358759(v=vs.110).aspx
I created the code to fix my error;
public class LogResolver : DataContractResolver
{
public override bool TryResolveType(Type dataContractType, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
{
if (dataContractType != typeof(LogViewModel))
{
return knownTypeResolver.TryResolveType(dataContractType, declaredType, null, out typeName,
out typeNamespace);
}
var dictionary = new XmlDictionary();
typeName = dictionary.Add("Log");
typeNamespace = dictionary.Add("http://tempuri.com");
return true;
}
public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
{
if (typeName == "Log" && typeNamespace == "http://tempuri.com")
{
return typeof(LogViewModel);
}
return knownTypeResolver.ResolveName(typeName, typeNamespace, null, null);
}
}
And
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
if (typeof(T).Name == "LogViewModel")
{
var writer = XmlDictionaryWriter.CreateDictionaryWriter(XmlWriter.Create(sessionData));
serializer.WriteObject(writer, data, new LogResolver());
}
else
{
serializer.WriteObject(sessionData, data);
}
But now my code will not compile because the serializer.WriteObject method does not take 3 parameters. How can this be? Surely MSDN cannot be wrong?
EDIT I decided to look at the definition of the serialisation class where WriteObject resides and I found this;
// Decompiled with JetBrains decompiler
// Type: System.Runtime.Serialization.XmlObjectSerializer
// Assembly: System.Runtime.Serialization.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// MVID: 94FDD0A8-CB5D-4815-A53D-5DC4F6C5FA80
// Assembly location: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.6\Profile\Profile32\System.Runtime.Serialization.Xml.dll
using System.IO;
using System.Xml;
namespace System.Runtime.Serialization
{
public abstract class XmlObjectSerializer
{
protected XmlObjectSerializer();
public abstract bool IsStartObject(XmlDictionaryReader reader);
public virtual bool IsStartObject(XmlReader reader);
public virtual object ReadObject(Stream stream);
public virtual object ReadObject(XmlDictionaryReader reader);
public abstract object ReadObject(XmlDictionaryReader reader, bool verifyObjectName);
public virtual object ReadObject(XmlReader reader);
public virtual object ReadObject(XmlReader reader, bool verifyObjectName);
public abstract void WriteEndObject(XmlDictionaryWriter writer);
public virtual void WriteEndObject(XmlWriter writer);
public virtual void WriteObject(Stream stream, object graph);
public virtual void WriteObject(XmlDictionaryWriter writer, object graph);
public virtual void WriteObject(XmlWriter writer, object graph);
public abstract void WriteObjectContent(XmlDictionaryWriter writer, object graph);
public virtual void WriteObjectContent(XmlWriter writer, object graph);
public abstract void WriteStartObject(XmlDictionaryWriter writer, object graph);
public virtual void WriteStartObject(XmlWriter writer, object graph);
}
}
So there is not WriteObject method that uses DataContractResolver. So what shall I do?
EDIT - A workaround not a solution. If you look at the error message the problem was that the objects being written contained an event which could not be serialised. This event was defined in the BaseViewModel class used in all ViewModels. So I created a new base class only to be used by those ViewModels that need it, as follows; namespace M.Survey.UILogic.ViewModels { using M.Survey.UILogic.Helpers; using Microsoft.Practices.Prism.PubSubEvents;
public class BaseEventViewModel : BaseViewModel
{
public BaseEventViewModel()
{
this.EventAgg = EventAggHolder.EventAgg;
}
public IEventAggregator EventAgg { get; set; }
}
So my problem is now fixed. But it leaves open how to write an object that contains an event. In WinRT I was unable to find an attribute that could exclude the event from serialisation that causes this bug.