Search code examples
c#async-awaitcomet

Comet-Style API Consumption with Async/Await


I'm trying to read from a Comet style HTTP API which you connect to and it continuously pushes events. I want this to run in the background after it's started, but my Async/Await is erroneous it's freezing my UI and I don't know why.

private async void button1_Click(object sender, EventArgs e)
{
    await Task.Run((Func<Task>)PushEventReader);
}

public async Task PushEventReader()
{
    var uri = "url.to/api";
    var client = new WebClient();

    client.OpenReadCompleted += async (sender, e) =>
    {
        using (var reader = new StreamReader(e.Result))
        {
            while (!reader.EndOfStream)
            {
                var line = await reader.ReadLineAsync();
                Console.WriteLine(line);
            }
        }
    };
    await client.OpenReadTaskAsync(new Uri(uri));
}

Solution

  • If your button click event does not anything other than start a job in the background then there's no point in making asynchronous with async and there's no point in awaiting the Task.Run since you are not doing anything after that. You can simply have your button click like this:

    private void button1_Click(object sender, EventArgs e)
    {
        Task.Run(async () => await PushEventReader());
    }
    

    Task.Run will queue whatever work you pass to it to run on the ThreadPool which will effectively make it run on the background.

    Extra: the WebClient you are using is an un-managed resource (you can notice that since it implements the IDisposable interface) and it is a good practice to use them inside a using block which will handle the disposing for you:

    public async Task PushEventReader()
    {
        var uri = "url.to/api";
    
        using (var client = new WebClient())
        {
            client.OpenReadCompleted += async (sender, e) =>
            {
                using (var reader = new StreamReader(e.Result))
                {
                    while (!reader.EndOfStream)
                    {
                        var line = await reader.ReadLineAsync();
                        Console.WriteLine(line);
                    }
                }
            };
    
            await client.OpenReadTaskAsync(new Uri(uri));
        }
    }