This post and the helper class is based on the work of Jamie Thomson. I thank him a lot for that. Now the question arises:
Why to use Metro Application Isolated Storage Helper?
This helper class helps you to perform Reads, Writes and Deletes of structured data in Isolated storage folders.
How to use this?
- Download the XAML Metro Application Isolated Storage Helper from here
- Add a reference of XAMLMetroAppIsolatedStorageHelper.dll
- Add the namespace as in: using XAMLMetroAppIsolatedStorageHelper;
You have a class Student
public class Student
{
public string Name { get; set; }
public int RollNumber { get; set; }
}
You want to save an object of Student then you can save it in a Local Folder of isolated storage as below:
Student objStudent = new Student { Name = "DJ ", RollNumber = 1 };
var objectStorageHelper = new StorageHelper<Student>(StorageType.Local);
objectStorageHelper.SaveASync(objStudent,"abc");
And you can read back the Student from isolated storage as below:
public async void ReadData()
{
var objectStorageHelper = new StorageHelper<Student>(StorageType.Local);
Student objStudent = await objectStorageHelper.LoadASync("abc");
}
ABC is a name of a file.
If you want to store List<Student> then you can do that as in the following:
List<Student> lstStudent = new List<Student>()
{new Student { Name = "DJ ", RollNumber = 1 },
new Student { Name = "debugmode", RollNumber = 2 }
};
var objectStorageHelper = new
StorageHelper<List<Student>>(StorageType.Local);
objectStorageHelper.SaveASync(lstStudent, "abc");
You can read List<Student> from the local folder of isolated storage as in the following:
public async void ReadData()
{
var objectStorageHelper = new
StorageHelper<List<Student>>(StorageType.Local);
List<Student> lstStudent = await objectStorageHelper.LoadASync("abc");
foreach (var r in lstStudent)
{
string n = r.Name;
}
}
Background
I was working with storing and retrieving structured data in Isolated Storage. While Binging I came across a nicely written Generic Object Storage Helper for WinRT. This is written by Jamie Thomson. When I tried using this utility I came across an exception. I tried to store a Student object as in the following:
private void btnSaveData_Click_1(object sender, RoutedEventArgs e)
{
Student objStudent = new Student { Name = "Hary ", RollNumber = 1 };
var objectStorageHelper = new
ObjectStorageHelper<Student>(StorageType.Local);
objectStorageHelper.SaveASync(objStudent);
}
But while running the program I came across the exception as below:
After inspecting I found that the library is written in Developer Preview and a few APIs have been changed in the Consumer Preview. Thankfully Jamie Thomson has put the source code on the CodePlex also. A big thank to him for that. Rather than adding a DLL and working with the API, I copied and pasted code in my program and started to debug that.
The first changes in the API from DP to CP was that there were no TryMoveToRecycleBin in the StorageDeleteOption enum:
Now the StorageDeleteOption enum contains only two values as below:
So I replaced the above line of code as below:
The second change from DP to CP I found was removal of the OpenWrite and OpenRead method from IRandomAcccessStream interface:
Where readStream is defined as below.
OpenRead has been replaced with AsStreamForRead.
And OpenWrite has been replaced with AsStreamForWrite.
I have modified the code to explicitly take a filename as well. After these changes have been done the code was ready to be used in Consumer Preview. The updated helper class code is as follows:
public enum StorageType
{
Roaming, Local, Temporary
}
public class ObjectStorageHelper<T>
{
private ApplicationData appData = Windows.Storage.ApplicationData.Current;
private XmlSerializer serializer;
private StorageType storageType;
public ObjectStorageHelper(StorageType StorageType)
{
serializer = new XmlSerializer(typeof(T));
storageType = StorageType;
}
public async void DeleteASync(string FileName)
{
FileName = FileName + ".xml";
try
{
StorageFolder folder = GetFolder(storageType);
var file = await GetFileIfExistsAsync(folder, FileName);
if (file != null)
{
await file.DeleteAsync(StorageDeleteOption.PermanentDelete);
}
}
catch (Exception)
{
throw;
}
}
public async void SaveASync(T Obj,string FileName)
{
FileName = FileName + ".xml";
try
{
if (Obj != null)
{
StorageFile file = null;
StorageFolder folder = GetFolder(storageType);
file = await folder.CreateFileAsync(FileName, CreationCollisionOption.ReplaceExisting);
IRandomAccessStream writeStream = await file.OpenAsync(FileAccessMode.ReadWrite);
Stream outStream = Task.Run(() =>writeStream.AsStreamForWrite()).Result;
serializer.Serialize(outStream, Obj);
}
}
catch (Exception)
{
throw;
}
}
public async Task<T> LoadASync(string FileName)
{
FileName = FileName + ".xml";
try
{
StorageFile file = null;
StorageFolder folder = GetFolder(storageType);
file = await folder.GetFileAsync(FileName);
IRandomAccessStream readStream = await file.OpenAsync(FileAccessMode.Read);
Stream inStream = Task.Run(() => readStream.AsStreamForRead()).Result;
return (T)serializer.Deserialize(inStream);
}
catch (FileNotFoundException)
{
//file not existing is perfectly valid so simply return the default
return default(T);
//throw;
}
catch (Exception)
{
//Unable to load contents of file
throw;
}
}
private StorageFolder GetFolder(StorageType storageType)
{
StorageFolder folder;
switch (storageType)
{
case StorageType.Roaming:
folder = appData.RoamingFolder;
break;
case StorageType.Local:
folder = appData.LocalFolder;
break;
case StorageType.Temporary:
folder = appData.TemporaryFolder;
break;
default:
throw new Exception(String.Format("Unknown StorageType: {0}", storageType));
}
return folder;
}
private async Task<StorageFile> GetFileIfExistsAsync(StorageFolder folder, string fileName)
{
try
{
return await folder.GetFileAsync(fileName);
}
catch
{
return null;
}
}
}
In this way you can work with structured data in a XAML based Metro Application for Windows 8. I hope this post is useful. Thanks for reading.