Reputation: 736
I'm developing a music metro style app. I'm getting all music files from users music library
I want to store StorageFile
object, because i don't want to retrieve again and again.To do this i tried serialize StorageFile
object and store it into XML
. From the examples here and here i tried to generate XML
file, but it throws an exception on creating XML file saying
Type 'Windows.Storage.StorageFile' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
So far my code is below,
namespace CloudMusic.AppSettings
{
[KnownType(typeof(CloudMusic.AppSettings.MusicFileDict))]
[DataContractAttribute]
public class MusicFileDict
{
[DataMember]
public object musicStorageFile { get; set; }
[DataMember]
public int id { get; set; }
}
}
and from below class I'm generating XML
class GenerateMusicDict
{
private const string filename = "musiclist.xml";
static private List<MusicFileDict> _data = new List<MusicFileDict>();
static public List<MusicFileDict> Data
{
get { return _data; }
}
static async public Task Save<T>()
{
await Windows.System.Threading.ThreadPool.RunAsync((sender) => GenerateMusicDict.SaveAsync<T>().Wait(), Windows.System.Threading.WorkItemPriority.Normal);
}
internal static async Task SaveAsync<T>()
{
GenerateMusicDict.GenerateMusicFileDict();
try
{
StorageFile sessionFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
IRandomAccessStream sessionRandomAccess = await sessionFile.OpenAsync(FileAccessMode.ReadWrite);
IOutputStream sessionOutputStream = sessionRandomAccess.GetOutputStreamAt(0);
var sessionSerializer = new DataContractSerializer(typeof(List<MusicFileDict>), new Type[] { typeof(T) });
sessionSerializer.WriteObject(sessionOutputStream.AsStreamForWrite(), _data);
await sessionOutputStream.FlushAsync();
}
catch (Exception)
{
}
}
/// <summary>
/// Generate music file dictonary according to songs ID
/// </summary>
/// <param name="musicFileList"></param>
private static void GenerateMusicFileDict()
{
List<StorageFile> music_file_list = MusicFileDict.GetMusicList(); // At this stage i'll get all my music files,GetMusicList() function returns List<StorageFile>
for (int i = 0; i < music_file_list.Count; i++)
{
_data.Add(new MusicFileDict { id = i, musicStorageFile = music_file_list[i]});
}
}
}
and calling Save method from my main class using
await GenerateMusicDict.Save<MusicFileDict>();
On SaveAsync() function at this line
sessionSerializer.WriteObject(sessionOutputStream.AsStreamForWrite(), _data);
it's firing an Exception
saying
Type 'Windows.Storage.StorageFile' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types. so how can i serialize it? or is there any way that i can store it and re-use. Please help me
Upvotes: 5
Views: 4496
Reputation: 611
Make use of the FutureAccessList http://msdn.microsoft.com/library/windows/apps/BR207457 it should provide the functionality you're looking for.
You can retrieve and access the files by referencing their paths. These paths can easily be stored and serialized (for example as a List).
This also alleviates any permissions issues you might run into if you want your app to be able to access user content that is outside of the Music Library.
Upvotes: 3
Reputation: 7700
Apparently from your code it seems like you are trying to serialize a music file in another file, which is quite of an overkill. So instead of trying to serialize music just make a reference to it using a URI.
[DataContractAttribute]
public class MusicFileDict
{
[DataMember]
public Uri MusicFileUri { get; set; }
[DataMember]
public int Id { get; set; }
}
Then create your objects like this
private static void GenerateMusicFileDict()
{
List<StorageFile> music_file_list = MusicFileDict.GetMusicList();
for (int i = 0; i < music_file_list.Count; i++)
{
StorageFile currentFile = music_file_list[i];
_data.Add(new MusicFileDict
{
Id = i,
MusicFileUri = new Uri(currentFile.Path)
});
}
}
If you need to keep a reference to the music file that you can manage, you could probably copy the music file to your local folder and reference this URI path instead. But keep in mind that music files can be heavy and that storage could precious, especially on WinRT devices.
On another note, please close your streams!
IRandomAccessStream sessionRandomAccess = null;
try
{
StorageFile sessionFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
sessionRandomAccess = await sessionFile.OpenAsync(FileAccessMode.ReadWrite);
IOutputStream sessionOutputStream = sessionRandomAccess.GetOutputStreamAt(0);
var sessionSerializer = new DataContractSerializer(typeof(List<MusicFileDict>), new Type[] { typeof(T) });
sessionSerializer.WriteObject(sessionOutputStream.AsStreamForWrite(), _data);
await sessionOutputStream.FlushAsync();
}
catch (Exception)
{
}
finally
{
sessionRandomAccess.Dispose();
}
Upvotes: 2