MovedCheeseException–where is StorageFolder.TryGetItemAsync in Windows Phone 8.1?

1 minute read

A quickie this time: when I finally started porting WpWinNl over to Windows Phone 8.1 (sorry, I was busy testing, preparing a talk and the Windows Phone Code Battle, so something had to give) and was getting into the nuts and bolts of some of my code I noticed something peculiar. Somewhere in my code the StorageHelper class, that sports this little method.

private async Task<StorageFile> GetDataFile()
{
  var result = 
    await ApplicationData.Current.LocalFolder.TryGetItemAsync(GetDataFileName(typeof(T)));
  return result as StorageFile;
}

got a compiler error on the TryGetItemsAsync method. So although Microsoft works hard on convergence for Windows Phone and Windows, apparently for some reason this method did not make the cut. In a Windows Phone / Windows 8.1 PCL it is not available either.

Now of course you can cry foul and say that once again Microsoft is pulling the rug out from under you, the loyal developer, or something to that effect – or you can just solve the problem. Either you change the line that does not compile to something that does compile on all platforms, for instance

var files = await ApplicationData.Current.LocalFolder.GetFilesAsync();
var result = files.FirstOrDefault(p => p.Name == name);

Or if you are a really lazy bastard  - like me – and just want to leave existing code intact, you can just make an extension method that you tuck in a library like this:

using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.Storage;

namespace WpWinNl.Utilities
{
  /// <summary>
  /// Replaces the missing TryGetItemAsync method in Windows Phone 8.1
  /// </summary>
  public static class StorageFolderExtensions
  {
    public static async Task<IStorageItem> TryGetItemAsync(this StorageFolder folder, 
                                                           string name)
    {
      var files = await folder.GetItemsAsync().AsTask().ConfigureAwait(false);
      return files.FirstOrDefault(p => p.Name == name);
    }
  }
}

And we’re  done here. Sometimes your cheese moves a little. Deal with it, that’s what it takes to be a developer ;-). As this article basically talks about two lines of code, I will dispense with the sample solution this time if you don’t mind.

Thanks to Dave Smits for pointing out on Twitter that I should add AsTask().ConfigureAwait(false), which I did. As I am writing a library, I should not interfere with the developer's way of handling thread safety. Here is explained why.