Inconsistent Exceptions for WinRT File Operations

Recently I encountered strange and inconsistent behavior in exceptions being thrown by different file operations in WinRT. Let's start with a snippet:

var file = await Package.Current.InstalledLocation.GetFileAsync(@"\Assets\Text.txt");

Although there is a file named Text.txt in Assets folder of the application package, the above code throws an exception. If you were paying close attention while reading the code you might have even noticed the problem. There's no exception thrown in the first line, though. Instead the second line throws an ArgumentException:

Value does not fall within the expected range.

Strange, isn't it?

Let's take a closer look by putting a breakpoint on the second line. The problem lies in the value of file.Path property: C:\Users\Username\Documents\Visual Studio 2012\Projects\SlnName\ProjName\bin\Debug\AppX\\Assets\Text.txt. Did you notice the two backslashes before the Assets folder? They're causing the problem. CopyAsync method can't find the file because of it and throws the non-descriptive exception which doesn't really help pinpointing its cause. Calling ReadTextAsync on the file instead would've make it much easier:

var file = await Package.Current.InstalledLocation.GetFileAsync(@"\Assets\Text.txt");
var text = await FileIO.ReadTextAsync(file);

In this case the second line throws FileNotFoundException:

The filename, directory name, or volume label syntax is incorrect.

Definitely much clearer. Too bad, CopyAsync doesn't throw the same exception. It would have made troubleshooting the original issue much easier.

That's not all, though. I still think the exception should already be thrown in the first line. If we replace the filename with a non-existent one (e.g. Text1.txt), it does throw FileNotFoundException as expected:

The system cannot find the file specified.

It seems that for some reason GetFileAsync can handle paths with double backslashes. It even sets file.DateCreated correctly, so there can be no doubt about that. The other methods don't seem to support this same syntax. That's not a problem per se, but in my opinion all methods should behave the same to avoid confusion: either support the syntax or not. Until that happens, I'll keep in mind the described anomaly, just in case I stumble upon it again.

Creative Commons License