Search code examples
c#winformstaskmessage-loop

Why does Task.WaitAll hang when a form is launched directly in Main()?


I've added a splash-screen form to a C# WinForms application to display while the application is being initialized/checking for updates. I'm using Squirrel.Windows to check for updates in Program.cs.

After adding the splash-screen, a call to Task.WaitAll in Main() never returns. This call worked as I expected before adding the splash-screen.

What can I do to ensure that the task completes in Main() while the splash-screen is displayed in the foreground?

Working example:

static void Main()
    {
        try
        {
            using (var mgr = new UpdateManager("xxxx"))
            {
                var task = mgr.UpdateApp();
                task.RunSynchronously();
                Task.WaitAll(task);
                Console.WriteLine(task.Status);
            }
        }
        catch (Exception ex)
        {
            logger.Debug(ex.Message);
        }

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new XForm());
    }

Non-working example:

static void Main()
    {
        var ss = new SplashScreen();
        Application.Run(ss);
        try
        {
            using (var mgr = new UpdateManager("xxxx"))
            {
                var task = mgr.UpdateApp();
                task.RunSynchronously();
                Task.WaitAll(task);
                Console.WriteLine(task.Status);
            }
        }
        catch (Exception ex)
        {
            logger.Debug(ex.Message);
        }
        ss.Close(); 
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new XForm());
    }

I've read a bunch of SO posts describing lock-up on Task.WaitAll, but I can't find a direct explanation of the phenomena I'm seeing here i.e.
Synchronously waiting for an async operation, and why does Wait() freeze the program here

How would I run an async Task<T> method synchronously?

I did try the suggestion of calling task.RunSynchronously() but it seemed to make no difference.


Solution

  • You can solve this problem using one of two approaches.

    Change to C# 7.1 and make your main method ASYNC Right click project > Build > Advanced > C# latest Minor Version

    static async Task Main()
    {
        try
        {
            using (var mgr = new UpdateManager("xxxx"))
            {
                await mgr.UpdateApp();
            }
        }
        catch (Exception ex)
        {
            logger.Debug(ex.Message);
        }
    
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new XForm());
    }
    

    Or

    If UpdateApp returns a value

    use .Result

    If UpdateApp does not return a value

    use .Wait()

    static void Main()
    {
        try
        {
            using (var mgr = new UpdateManager("xxxx"))
            {           
                mgr.UpdateApp().Wait();             
            }
        }
        catch (Exception ex)
        {
            logger.Debug(ex.Message);
        }
    
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new XForm());
    }