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"); file.CopyAsync(ApplicationData.Current.LocalFolder);
Although there is a file named
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
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
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
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.