MatthieuGD
MatthieuGD

Reputation: 4602

Deserialization and Async/Await

In my app (Windows 8 Metro) I store some objects in the local Folder in a serialized format. Here's the method to read then back (see below).

If I call this method with Task.Run, I can get the object:

var entity= Task.Run<Entity>(() => GetASync<Entity>(file)).Result;

but if I use the await keyword, it's not working - on the line A (ReadObject) in the method the thread stops and exit with no error or exception:

var entity= await GetASync<Entity>(file);

Maybe I don't use await / async as it's recommended?

The method

private async Task<T> GetASync<T>(IStorageFile file) where T : class
{
    try
    {    
        if (file != null)
        {
            IRandomAccessStream readStream = await file.OpenAsync(FileAccessMode.Read);
            IInputStream inputStream = readStream.GetInputStreamAt(0);                   
            using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(inputStream.AsStream(), XmlDictionaryReaderQuotas.Max))
            {
                DataContractSerializer serializer = new DataContractSerializer(typeof(T));
                var entity = serializer.ReadObject(reader); //line A - here the problem 
                return entity as T;
            }                    
        }
        else
        {
            return null;
        }

    }
    catch (FileNotFoundException)
    {
        return null;
    }
    catch (Exception)
    {
        throw;
    }
}

Upvotes: 3

Views: 3176

Answers (2)

Gragus
Gragus

Reputation: 94

Ping-back from http://social.msdn.microsoft.com/Forums/en-US/async/thread/3f192a81-073a-47ea-92e2-5ce02bf5ad33:

You are hitting a known issue in the .NET developer preview version that Microsoft distributed at the BUILD conference. The issue is caused by some subtle specifics of the WinRT UI thread. As a result, any blocking WinRT stream-IO from managed code will lead to a deadlock, if performed from the UI thread. Asynchronous IO (e.g. ReadAsync) will work fine. The development team is aware of the problem and is working to fix it.

Please note, however, that even if and when the issue is fixed, performing blocking IO on the UI thread is not a good idea. Your application will block and be unresponsive for the duration of the operation. Some .NET APIs do not have async equivalents (yet) and even once they do, converting code may require work. If you have to perform a blocking IO operation, make sure to offload it to the thread pool:

DoUIStuff();
Int32 x = await Task.Run(() => {
    OpenStream();
    PerformBlockingIO();
    ProcessResults();
    return ComputeIOResults();
});
UseIOResults(x);

This way you keep your application responsive at all times. As a side effect, you will also work around the abovementioned bug and avoid the deadlock.

Upvotes: 1

Stephen Cleary
Stephen Cleary

Reputation: 457137

Well, I have no idea why your code doesn't work. I'm suspecting a deadlock, but there shouldn't be one. :)

However, I do have a couple performance recommendations that would probably avoid the problem as a side effect. The first is to use ConfigureAwait(false):

IRandomAccessStream readStream = await file.OpenAsync(FileAccessMode.Read)
                                           .StartAsTask()
                                           .ConfigureAwait(false);

The other is to read the file into memory (asynchronously) and then parse it. (I'm assuming from your code that you're storing one object per file).

Upvotes: 3

Related Questions