ArgumentException when calling StorageFolder.GetFolderFromPathAsync at the same time

I get ArgumentExceptions when there are several calls in Windows.Storage.StorageFolder.GetFolderFromPathAsync for different threads. Here is a test that reproduces the problem:

[TestMethod] public async Task ConcurrentGetFolderFromPath() { List<Task> tasks = new List<Task>(); for (int i = 0; i < 10; i++) { var task = Task.Run(async () => { string localFolderPath = Windows.Storage.ApplicationData.Current.LocalFolder.Path; //await Task.Yield(); var folder = await Windows.Storage.StorageFolder.GetFolderFromPathAsync(localFolderPath); }); tasks.Add(task); } await Task.WhenAll(tasks); } 

Here is the exception I get:

 System.ArgumentException: Value does not fall within the expected range. Result StackTrace: at Windows.Storage.StorageFolder.GetFolderFromPathAsync(String path) at PCLStorage.Test.FolderTests.<<ConcurrentGetFolderFromPath>b__53>d__55.MoveNext() in c:\git\pclstorage\test\PCLStorage.Test\FolderTests.cs:line 205 

The test does not work sequentially for me when I run it on my own, but usually passes when I run it along with the rest of the PCL Storage tests.

Am I doing something wrong here? Are GetFolderFromPathAsync or any other APIs that I use only for use from a UI thread? Or is this possibly a bug in the WinRT APIs?

+4
source share
1 answer

Ok, so the problem here is one of Task.Run and the way it is handled by async delegates . Basically when you say:

 Task.Run(async () => ...) 

What it returns to you is not the usual jane Task that you expect from it. He returns this task wrapped in another task, that is, a task. Therefore, to get the job you are looking for (the one that retrieves the StorageFolder), you need to await external task. You can do this simply by changing by adding it to the tasks list:

 tasks.Add(await task); 

Now there is a second problem. You are doing a bunch of reading from the same folder, possibly at the same time. This may cause some AccessExceptions . It may also not be. I will just be careful about this.

I had problems reading / writing files in unit tests in WinRT. Fortunately, I use Mvvm (via Mvvm Light) and wrapped the local storage available inside Controller . This allowed me to write LocalStorageController only for unit testing, which allows me to execute all my IOs in the file system in memory (basically a simple Dictionary<string, byte[]> ). This makes it difficult to test complex file trees, but you can also use a different data structure (for example, the actual Tree ) to model your file system.

Anyway, I hope this helps. I apologize that it was so long after you asked about it. Happy coding!

0
source

Source: https://habr.com/ru/post/1484124/


All Articles