Ms01
Ms01

Reputation: 4712

How to solve this deadlock?

I have an UWP application in which I am trying to store and retrieve some data from a local text file but no matter how I try to do it the application gets deadlocked. Due to synchronous stuff that needs to happen, I try to use a task and wait for its completion but nevertheless, the application locks.

I have a page in my UWP application called "MainPage" and in it's constructor I have the following code:

var listenkeyViewModel = new ListenkeyViewModel();
listenkeyViewModel.GetKey();
listenkey = listenkeyViewModel.Listenkey;

The get key is the issue here because it calls a method on the ViewModel (which I created to be synchronous because I thought making the call synchronous asap would be preferable.

public void GetKey()
{
    try
    {
        var listenKeyTask = RetrieveListenKey();
        _listenkey = listenKeyTask.Result;
    }
    catch (Exception e)
    {
    }
}

public static async Task<string> RetrieveListenKey()
{
    try
    {
        var storageFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
        var listenkeyFile = await storageFolder.GetFileAsync("listenkey.txt");
        return await Windows.Storage.FileIO.ReadTextAsync(listenkeyFile);
    }
    catch (Exception e)
    {
        throw new Exception("Could not load file");
    }
}

I know the thing is "async all the way down" but this is not possible here. I cannot make the constructor where the original code lies asynchronous. How are you supposed to not get deadlocked? I do not understand.

Upvotes: 2

Views: 321

Answers (1)

Nkosi
Nkosi

Reputation: 247343

Convert GetKey to async/await

public async Task GetKey() {
    try {
        var listenKeyTask = RetrieveListenKey();
        _listenkey = await listenKeyTask;
    } catch (Exception e) {
        //...should handle/log error
    }
}

Move the calling of this out of the constructor and into an event handler. like page load or some other event called early in the lifecycle of the page.

partial class MainPage : Page {
    ListenkeyViewModel listenkeyViewModel;
    string listenkey;

    public MainPage() {
        InitializeComponent();
        listenkeyViewModel = new ListenkeyViewModel();
        // add a handler to be called when the page has been loaded
        this.Loaded += OnPageLoaded;             
    }

    async void OnPageLoaded(object sender, RoutedEventArgs e) {            
        await listenkeyViewModel.GetKey();
        listenkey = listenkeyViewModel.Listenkey;
    }

    // Shown for demonstration purposes only.
    // This is typically autogenerated by Visual Studio.
    private void InitializeComponent() {
    }
}

async void is allowed on event handlers so this should allow the process to flow without deadlock.

Upvotes: 3

Related Questions