Question

I am using PCLStorage library in my project so that I can access filesystem from my PCL lib. I am trying to read a file as follows:

static async Task<T> LoadAsync<T> (string fileName) where T : class
    {
        var rootFolder = FileSystem.Current.LocalStorage; // debugger stops here
        var m5cacheFolder = await rootFolder.GetFolderAsync (CacheFolderName); // but instead of going to this line, jumps to end of this method
        var userInfoFile = await m5cacheFolder.GetFileAsync (fileName);
        var userInfoFileContent = await userInfoFile.ReadAllTextAsync ();
        var stringReader = new StringReader (userInfoFileContent);
        var serializer = new XmlSerializer (typeof(T));
        return (T)serializer.Deserialize (stringReader);
    }

Since PCLStorage is asynchronous and I want to use it in a syncrhonous code I am calling it like this:

var task = LoadAsync<User> (UserInfoFileName);
user = task.Result;

The problem is that whole application freezes when I try to execute this code. As described in comments above, the code in LoadAsync method is not executed. I am using newest Xamarin 3. My PCL library is referenced in Xamarin iOS project. Both projects have references to PCLStorage through nugget.

On the other hand following code is executed correctly:

static async void PersistAsync (object obj, string fileName)
    {
        var rootFolder = FileSystem.Current.LocalStorage;
        var m5cacheFolder = await rootFolder.CreateFolderAsync (CacheFolderName, CreationCollisionOption.OpenIfExists);
        var userInfoFile = await m5cacheFolder.CreateFileAsync (fileName, CreationCollisionOption.ReplaceExisting);
        var serializer = new XmlSerializer (obj.GetType ());
        var stringWriter = new StringWriter ();
        serializer.Serialize (stringWriter, obj);
        await userInfoFile.WriteAllTextAsync (stringWriter.ToString ());
    }
Was it helpful?

Solution

This is always a potential recipe for disaster:

var task = LoadAsync<User>(UserInfoFileName);
user = task.Result;

If this is happening in the UI thread, then you're basically blocking the UI thread until the task has completed - but the task will need to execute its continuations on the UI thread too. You've got a deadlock.

Basically you should be trying to structure your app to embrace asynchrony more. You could use Task.ConfigureAwait() to schedule the continuations in LoadAsync to execute on thread-pool threads instead, but you're still going to be blocking the UI until it's completed, which is against the spirit of asynchrony.

Asynchrony is somewhat viral - if you try to make just one part of your app asynchronous, you're going to have a hard time. You need to be asynchronous all the way up, at least in terms of UI operations.

(If you block waiting for the task returned by PersistAsync you'll have a similar issue, by the way.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top