director, software developer, qualified tas / ict teacher.

Published: 3 years ago

Storing and Retrieving complex objects in Json using Windows 8.1 C#

Read below or skip right to the demo project, ignoring the terrible demo UI: https://github.com/LucasMoffitt/Save-and-Read-Json-Objects-Windows-8.1

So far, 90% of the Windows 8 apps I’ve written require storing data for later, or reading data that was stored earlier. There’s a million different ways to do it, but I’ve had great success with json.net and serialising / storing data this way. The only problem you have is when dealing with multiple types, and trying to figure out the best way to do it.

I’m not saying it’s the best way, but here’s what I’ve found that covers all of my requirements. I’ve condensed the class to make it easy for everyone to use, and you can even see it in action from the demo project.

This is the base abstract generic class called StorageBase, it will be responsible for all our heavy lifting.

public abstract class StorageBase<T> where T : Identifiers
{
    protected abstract string FolderName { get; }
    private const string FileFormat = ".json";
    private readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects };

    protected virtual async Task<StorageFolder> StorageFolder()
    {
        return await ApplicationData.Current.LocalFolder.CreateFolderAsync(FolderName, CreationCollisionOption.OpenIfExists);
    }

    public async Task<T> Get(Guid id)
    {
        if (!await DoesFileExist(id))
            return default(T);

        var file = await GetStorageFile(id);
        var fileContent = await FileIO.ReadTextAsync(file);

        return fileContent == null ? default(T) : JsonConvert.DeserializeObject<T>(fileContent, _serializerSettings);
    }

    public async Task<T> Save(T data)
    {
        StorageFile file;
        if (await DoesFileExist(data.Id))
        {
            file = await GetStorageFile(data.Id);
        }
        else
        {
            var folder = await StorageFolder();
            file = await folder.CreateFileAsync(data.Id + FileFormat);
        }

        await FileIO.WriteTextAsync(file, JsonConvert.SerializeObject(data, _serializerSettings));

        return data;
    }

    public async void Delete(Guid id)
    {
        if (!await DoesFileExist(id))
            return;

        var file = await GetStorageFile(id);
        await file.DeleteAsync();
    }

    protected async Task<bool> DoesFileExist(Guid id)
    {
        return await GetStorageFile(id) != null;
    }

    protected async Task<StorageFile> GetStorageFile(Guid id)
    {
        var folder = await StorageFolder();
        var files = await folder.GetFilesAsync();

        return files.FirstOrDefault(file => file.Name == id.ToString() + FileFormat);
    }

    public async Task<ObservableCollection<T>> All()
    {
        var all = new ObservableCollection<T>();
        var folder = await StorageFolder();
        var files = await folder.GetFilesAsync();

        foreach (var file in files)
        {
            var fileContent = await FileIO.ReadTextAsync(file);
            var item = JsonConvert.DeserializeObject<T>(fileContent, _serializerSettings);
            all.Add(item);
        }

        return all;
    }
}
1

What make this class awesome:

  • It deals with the get, getall, save and delete methods you’d expect with a storage system.
  • It requires the implementing class overrides the folder name property to split content into different folders of your Windows 8.1 app root.
  • It implements a constraint on the domain which looks like this…

The reason for that is due to how I name the files, no reason you couldn’t do it another way however.

Putting two and two together, this means that in order to manage multiple different object types as files, you can just create your domain model which inherits Identifiers, and a class which Inherits from StorageBase and call methods against it as per normal.

For example:

public class Person : Identifiers
{
  public string Name { get; set; }
  public string Email { get; set; }
}

public class PersonStorage : StorageBase<Person>
{
  protected override string FolderName
  {
    get { return "People"; }
  }
}

public class Test
{
  public async void Execute()
  {
    var personStorage = new PersonStorage();
    var allItems = await personStorage.All();

    var newPerson = new Person
    {
      Name = "Lucas Moffit",
      Email = "LucasMoffitt@gmail.com"
    };

    await personStorage.Save(newPerson);
  }
}

Hope this makes it easier to store complex objects in windows 8.1

Have a Comment?

Some HTML is OK