06 May 2014

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

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.

4 comments:

Raffaele Rialdi said...

You should also try/catch and return false in case of failure.
The new Try... API is not expected to throw if the file does not exists.

Joost van Schaik said...

@Raffaele true, but I have been taught exceptions are expensive performance-wise so I tend to avoid them

41South said...

Many thanks for this - I am amazed that there is simply no way to check a file exists in the local folder without resorting to the code above.

I know the cheese does move sometimes but the transition from WP8 to Wp8.1 is so ridiculous, there's just so much stuff changed, left out or not supported anymore! It makes it soooo frustrating porting apps or building new ones - I'm just spending all my time on google trying to find out why my well written and reliable WP8 code won't work!! TBH, compared with WP8, I'm not enjoying WP8.1 development much and as I'm not really doing universal apps I am seriously tempted to just target the WP8 platform and forgetting 8.1 until I really have to deal with it.

Joost van Schaik said...

41South right you are. Move to Windows 10 UWP :D