jzonthemtn
jzonthemtn

Reputation: 3414

Overriding function and including async/await

I have a class called WebUtil and in it is an abstract function called GetWebpage(). In one implementation of this function I use the WebClient class, in another I use the new HttpClient with its await/async functionality. Problem is the use of HttpClient requires the method to return Task<>, so I changed the abstract method definition. But now the function that uses the WebClient has to also return Task<>.

Is there a good way to handle this? Is there something I'm not familiar with?

Upvotes: 0

Views: 315

Answers (3)

svick
svick

Reputation: 244968

As Stephen Cleary mentioned in a comment, WebClient does support async too, so you can just call one of the -TaskAsync methods.

But in general, it's okay to implement async interface using either Task.FromResult() (if the method is fast), or Task.Run() (if it's slow).

Upvotes: 0

Kirill Shlenskiy
Kirill Shlenskiy

Reputation: 9587

You will have to stick with one or the other. Personally, I would pick async and rework the override which uses WebClient to return a Task. You will get more bang for your buck in terms of functionality (see the code snippet for CancellationToken support, for example). This also happens to be a better design due the non-blocking nature of this method.

    public override Task<string> GetWebpage(CancellationToken cancellationToken)
    {
        var client = new WebClient();
        var tcs = new TaskCompletionSource<string>();

        client.DownloadStringCompleted += (sender, e) =>
        {
            if (e.Cancelled)
            {
                tcs.SetCanceled();
            }
            else if (e.Error != null)
            {
                tcs.SetException(e.Error);
            }
            else 
            {
                tcs.SetResult(e.Result);
            }
        };

        client.DownloadStringAsync(this.Url);

        if (cancellationToken.CanBeCanceled)
        {
            cancellationToken.Register(client.CancelAsync);
        }

        return tcs.Task;
    }

Upvotes: 1

deerchao
deerchao

Reputation: 10544

You can return Task<> with the WebClient with Task.FromResult.

Task<string> GetWebPage(string url)
{
    var c = new WebClient();
    var html = c.DownloadString(url);
    return Task.FromResult(html);
}

Or, you can use TaskCompleteSource<T> convert events to task:

Task<string> GetWebPage(string url)
{
    var c = new WebClient();
    var tcs = new TaskCompleteSource<string>();
    c.DownloadStringCompleted += (o, e) => tcs.SetResult((string)e.Result);
    c.DownloadStringAsync(new Uri(url));
    return tcs.Task;
}

Upvotes: 3

Related Questions