I am trying to Serialize an ObservableCollection. But I am getting following error: Let me know how can I fix this?
Error:
{System.InvalidOperationException: There was an error reflecting type
‘System.Collections.ObjectModel.ObservableCollection1[eText.DataModel.BooksDownloadedData]'.1.MoveNext()
---> System.InvalidOperationException: There was an error reflecting type 'eText.DataModel.BooksDownloadedData'. --->
System.InvalidOperationException: Cannot serialize member
'eText.DataModel.BooksDownloadedData.DownloadedBookFileDetails' of
type 'Windows.Storage.StorageFile', see inner exception for more
details. ---> System.InvalidOperationException:
Windows.Storage.StorageFile cannot be serialized because it does not
have a parameterless constructor. --- End of inner exception stack
trace --- at
System.Xml.Serialization.StructModel.CheckSupportedMember(TypeDesc
typeDesc, MemberInfo member, Type type) at
System.Xml.Serialization.StructModel.GetPropertyModel(PropertyInfo
propertyInfo) at
System.Xml.Serialization.StructModel.GetFieldModel(MemberInfo
memberInfo) at
System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping
mapping, StructModel model, Boolean openModel, String typeName,
RecursionLimiter limiter) at
System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel
model, String ns, Boolean openModel, XmlAttributes a, RecursionLimiter
limiter) at
System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel
model, String ns, ImportContext context, String dataType,
XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter
limiter) --- End of inner exception stack trace --- at
System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel
model, String ns, ImportContext context, String dataType,
XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter
limiter) at
System.Xml.Serialization.XmlReflectionImporter.CreateArrayElementsFromAttributes(ArrayMapping
arrayMapping, XmlArrayItemAttributes attributes, Type
arrayElementType, String arrayElementNs, RecursionLimiter limiter)
at
System.Xml.Serialization.XmlReflectionImporter.ImportArrayLikeMapping(ArrayModel
model, String ns, RecursionLimiter limiter) at
System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel
model, String ns, ImportContext context, String dataType,
XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter
limiter) --- End of inner exception stack trace --- at
System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel
model, String ns, ImportContext context, String dataType,
XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter
limiter) at
System.Xml.Serialization.XmlReflectionImporter.ImportElement(TypeModel
model, XmlRootAttribute root, String defaultNamespace,
RecursionLimiter limiter) at
System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type
type, XmlRootAttribute root, String defaultNamespace) at
System.Xml.Serialization.XmlSerializer..ctor(Type type, String
defaultNamespace) at
System.Xml.Serialization.XmlSerializer..ctor(Type type) at
eText.Common.Xml.Serialize[T](Object obj, Type[] extraTypes) in
f:\TFS\New
TFS\PDFReader\Posh.PdfReader.Win8\eText\Common\Utility.cs:line 81
at
eText.Common.ApplicationSettings.<SaveDataToFileAsync>d__0
in f:\TFS\New
TFS\PDFReader\Posh.PdfReader.Win8\eText\Common\ApplicationSettings.cs:line
16
— End of stack trace from previous location where exception was thrown — at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task) at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at eText.ViewModel.MainViewModel.d__a.MoveNext() in
f:\TFS\New
TFS\PDFReader\Posh.PdfReader.Win8\eText\ViewModel\MainViewModel.cs:line
268}
Code That I am using to serialize:
Book Class:
[DataContract]
public class Book : ViewModelBase
{
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="Book" /> class.
/// </summary>
public Book(){}
/// <summary>
/// Initializes a new instance of the <see cref="Book" /> class.
/// </summary>
/// <param name="BookTitle">The book title.</param>
/// <param name="BookCategory">The book category.</param>
/// <param name="DownloadURL">The download URL.</param>
/// <param name="TotalNumberOfPages">The total number of pages.</param>
/// <param name="BookAuthor">The book author.</param>
/// <param name="ImageURL">The image URL.</param>
public Book(string BookTitle,string BookCategory,string DownloadURL, string TotalNumberOfPages, string BookAuthor, string ImageURL)
{
this.BookCategory = BookCategory;
this.BookTitle = BookTitle;
this.BookAuthor = BookAuthor;
this.TotalNumberOfPages = TotalNumberOfPages;
this.DownloadURL = DownloadURL;
this.ImageURL = ImageURL;
}
#endregion
}
BooksDownloadedData class
/// <summary>
/// Class to store downloaded books metaData
/// </summary>
[DataContract]
public class BooksDownloadedData
{
/// <summary>
/// The downloaded books detail
/// </summary>
[DataMember]
public Book DownloadedBooks { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is downloaded completed.
/// </summary>
/// <value>
/// <c>true</c> if this instance is downloaded completed; otherwise, <c>false</c>.
/// </value>
[DataMember]
public bool IsDownloadedCompleted { get; set; }
}
Created an ObservableCollection for BooksDownloadedData and then saving it in Local Storage after serializing but at time of serializing getting error:
// Create object to get the saved meta data of files
ObservableCollection<BooksDownloadedData> downLoadedFiles;
// Save the data to the local storage
await ApplicationSettings.SaveDataToFileAsync<ObservableCollection<BooksDownloadedData>>(fileName, downLoadedFiles);
public static async Task SaveDataToFileAsync<T>(string key, T value, bool roaming = false, Type[] extraTypes = null)
{
var file = roaming ? await ApplicationData.Current.RoamingFolder.CreateFileAsync(key + ".xml", CreationCollisionOption.ReplaceExisting) :
await ApplicationData.Current.LocalFolder.CreateFileAsync(key + ".xml", CreationCollisionOption.ReplaceExisting);
var xml = Xml.Serialize<T>(value, extraTypes);
await FileIO.WriteTextAsync(file, xml, UnicodeEncoding.Utf8);
}
public static string Serialize<T>(object obj, Type[] extraTypes = null)
{
using (var sw = new StringWriter())
{
var serializer = extraTypes == null ? new XmlSerializer(typeof(T)) : new XmlSerializer(typeof(T), extraTypes);
serializer.Serialize(sw, obj);
return sw.ToString();
}
}
The problem is the use of
Windows.Storage.StorageFile, which clearly isn’t intended to play nicely with serialization (or at least: notXmlSerializer).You might be able to refactor your model so that you don’t need to use
StorageFile. You might be able to mark that member (DownloadedBookFileDetails) with[XmlIgnore], and re-create theStorageFilemanually after deserialization. You might be able to use a different serializer (DataContractSerializer, JSON.NET, protobuf-net, etc).However! In most cases I see (and I deal with serialization a lot) the key mistake people make is trying to fight the serializer so that they can keep using their existing domain model. When actually, the simplest thing to do is usually: create a DTO: a separate model that is designed solely to represent the data as a bridge to serialization, and then map to/from the DTO model and your main domain model.
Not only does this invariably work really easily every time, it also puts you in a very strong position if you ever want to: