2013-06-01 1 views
0

У меня есть класс WebUtil, и в нем есть абстрактная функция, называемая GetWebpage(). В одной реализации этой функции я использую класс WebClient, в другом я использую новый HttpClient с его функциональностью await/async. Проблема в использовании HttpClient требует возврата метода Task<>, поэтому я изменил определение абстрактного метода. Но теперь функция, которая использует WebClient, должна также вернуть Task<>.Функция переадресации и в том числе async/await

Есть ли хороший способ справиться с этим? Есть ли что-то, с чем я не знаком?

+3

['WebClient.DownloadStringTaskAsync'] (http://msdn.microsoft.com/en-us/library/hh194010.aspx)? –

+0

Нам не хватает какого-либо контекста здесь, почему вы все еще используете WebClient и его версию, отличную от задачи, но знаете ли вы, что [Portable HttpClient теперь доступен как RTM] (http: //blogs.msdn .com/б/bclteam/архив/2013/05/29/портативный-HttpClient-это-теперь доступны по мере rtm.aspx)? –

+0

Да, Пауло. Мое открытие пакета NuGet для HttpClient - вот что привело меня сюда. Благодарю. – jbird

ответ

3

Вы можете вернуть Task<> с WebClient с Task.FromResult.

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

Или, вы можете использовать TaskCompleteSource<T> конвертировано события задачи:

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; 
} 
+0

См. Ответ Кирилла для обработки исключений. – deerchao

1

Вы должны придерживаться одного или другого. Лично я бы выбрал async и переработал переопределение, которое использует WebClient для возврата Задачи. Вы получите больше шансов для вашего доллара с точки зрения функциональности (см., Например, фрагмент кода для поддержки CancellationToken). Это также является лучшим дизайном из-за неблокирующего характера этого метода.

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; 
    } 
0

Как упоминалось Стивен Клири в комментарии, WebClient не поддерживает async, так что вы можете просто позвонить по одному из -TaskAsync методов.

Но в целом, можно реализовать интерфейс async, используя либо Task.FromResult() (если метод быстрый), либо Task.Run() (если он медленный).

+0

Что касается использования Task.Run (...) для инкапсуляции блокирующего вызова: я немного нацистский, когда дело доходит до этого. Создание задачи, которая может потенциально порождать новый поток * просто для его блокировки * Ожидание возврата синхронного метода DownloadString - это плохой выбор, когда есть совершенно хороший (хотя и старомодный) async api. –

+0

Сказав это, ваше другое предложение, которое включает в себя методы -TaskAsync, находится на месте. –

+0

@ Кирилл Шленский Да, ты прав, что это было бы расточительно. Я имел в виду, что вы должны использовать 'Task.Run()', если у вас длительная работа, у которой нет асинхронной альтернативы. – svick

Смежные вопросы