.NET Zone is brought to you in partnership with:

I am developer and technology maniac who is working on Microsoft and PHP technologies. I have ASP.NET MVP title and I hold MCAD, MCSD and MCTS certificates. When I have free time I usually play with new technologies, hack something, read books, participate in communities and speak in events. I am also active blogger and my ASP.NET blog is the place you can find some interesting reading about my discoveries and personal thoughts. Gunnar is a DZone MVB and is not an employee of DZone and has posted 136 posts at DZone. You can read more from them at their website. View Full User Profile

Generalizing Storage Access for Windows Phone and WinRT Apps

12.22.2013
| 2326 views |
  • submit to reddit

When building application that works both on WinRT and Window Phone you use Portable Class Libraries (PCL) for shared classes. As there are many application specific things that are not same on different platforms or that are not supported by PCL then you have to make some architectural decisions when creating shared functionalities. In this posting I will focus on persisting data for offline use.

Problem: Different storage implementations

As WinRT and Windows Phone application both use same data storing logic it is implemented in PCL to avoid duplicating the code. The class that needs to load and save data is defined in PCL but there is no generic storage interface or class defined in PCL that WinRT and Windows Phone applications can use.

pcl-storage-winrt-wp

The problem is: how to make storage operations on different platforms available to shared library that is used by applications running on different platforms and having different storage logic.

Breaking dependency to storage logic

Usually we have already one application written to some point when starting with another. When starting with another application we move shared functionality to PCL and find out that most of our original platform classes are not available there.

public interface IStorageProvider
{
    byte[] GetData();
    void SaveData(byte[] data);        
}

Next we make our DataManager class to use this interface to communicate with storage.

public class DataManager
{ 
    private readonly IStorageProvider _provider;
 
    public DataManager(IStorageProvider provider)
    {
        _provider = provider;
    }
 
    // ...
}

When DataManager class is created we give it some class that implements IStorageProvider interface and DataManager is happy.

Example: Windows Phone storage provider

Windows Phone uses isolated storage for application settings and files. Isolated storage is supported only in Windows Phone and therefore it is not supported by PCL. We have to define storage provider for Windows Phone in our Windows Phone application.

public class WindowsPhoneStorageProvider : IStorageProvider
{
    public byte[] LoadData()
    {
        using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
        {
            if (!storage.FileExists("data.dat"))
                return null;
 
            using (var file = storage.OpenFile("data.dat", FileMode.Open, FileAccess.Read, FileShare.None))
            {
                var data = new byte[file.Length];
                file.Read(data, 0, data.Length);
                return data;
            }
        }
    }
 
    public void SaveData(byte[] data)
    {
        using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
        {
            if (storage.FileExists("data.dat"))
                storage.DeleteFile("data.dat");
 
            using (var file = storage.OpenFile("data.dat", FileMode.Create, FileAccess.Write, FileShare.None))
            {
                file.Write(data, 0, data.Length);
                file.Flush(true);
            }
        }
    }
}

Example: WinRT storage provider

On WinRT we must write different code to use application storage. Here I’m using local storage for my data file.

public class WinRTStorageProvider : IStorageProvider
{
    public string UserName
    {
        get { return ""; }
    }
 
    public async void SaveData(byte[] data)
    {
        var storageFolder = ApplicationData.Current.LocalFolder;
        var file = await storageFolder.CreateFileAsync("data.dat", CreationCollisionOption.ReplaceExisting);
        using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
        using (var writer = new DataWriter(stream))
        {
            writer.WriteBytes(data);
            await writer.StoreAsync();
        }
    }
 
    public async Task<byte[]> ReadData()
    {
        var storageFolder = ApplicationData.Current.LocalFolder;
        var file = await storageFolder.GetFileAsync("data.dat");
        using (var stream = await file.OpenAsync(FileAccessMode.Read))
        using (var inputStream = stream.GetInputStreamAt(0))
        using (var reader = new DataReader(inputStream))
        {
            var data = new byte[stream.Size];
            await reader.LoadAsync((uint)data.Length);
            reader.ReadBytes(data);
            return data;
        }
    }
}

Wrapping up

Now we can use our DataManager in PCL library with different storage providers. DataManager knows storage providers by IStorageProvider interface, keeping itself away from storage implementations. Storage implementations are defined in specific applications or their libraries and these implementations are given to DataManager when data manager class is created. We can easily change internal storage logic if we need and we don’t have to modify code in another libraries.

Related Posts

The post Generalizing storage access for Windows Phone and WinRT apps appeared first onGunnar Peipman - Programming Blog.

Published at DZone with permission of Gunnar Peipman, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)