async
ключевое слово не сделать что-то работать в асинхронном режиме, он позволяет использовать await
в ждут уже асинхронной операции. Вы должны использовать DownloadStringTaskAsync действительно загрузить в асинхронном режиме:
internal async Task<string> LoadCompanyContracts(string URL)
{
....
using(var wc = new WebClient())
{
string tmp = await wc.DownloadStringTaskAsync(new Uri(URL));
return tmp;
}
}
await
самих по себе возвращает выполнение в контексте выполнения оригинала (то есть в потоке пользовательского интерфейса). Это может или не может быть нежелательно, поэтому код библиотеки обычно использует ConfigureAwait(false);
и позволяет конечному пользователю библиотеки, чтобы решить, как ждать:
string tmp = await wc.DownloadStringTaskAsync(new Uri(URL))
.ConfigureAwait(false);
Наконец, нет никакого смысла в ожидании, если вы собираетесь вызовите .Result
из функции верхнего уровня. Нет смысла использовать await
вообще, если вы не хотите использовать результат метода в своем коде. LoadCompanyContracts
может быть просто:
internal Task<string> LoadCompanyContracts(string URL)
{
....
using(var wc = new WebClient())
{
return wc.DownloadStringTaskAsync(new Uri(URL))
.ConfigureAwait(false);
}
}
Нам
Как правило, вам не нужно использовать поджидают на всех, если вы просто возвращает результат асинхронной операции. Метод мог бы только return wc.DownloadStringTaskAsync(..);
НО НОТА, который заставляет метод возвращать и перед тем, как закончите загрузку, удалите WebClient
. Избежать блока using
также не является решением, так как это позволит дорогостоящему объекту, например WebClient
, дольше, чем необходимо.
Вот почему HttpClient предпочтительнее WebClient
: один экземпляр поддерживает несколько одновременных вызовов, что означает, что вы можете иметь только один экземпляр, например, как поле и использовать его, например:
HttpClient _myClient =new HttpClient();
internal Task<string> LoadCompanyContractsAsync(string URL)
{
....
return _myClient.GetStringAsync(new Uri(URL))
.ConfigureAwait(false);
}
}
Вы можете избавиться от ваш DownloadString
, так как он ничего не делает сверху LoadCompanyContracts
.Если он использует результат LoadCompanyContracts
, следует переписать в виде:
internal async Task<string> DownloadString(string URL)
{
var result = await LoadCompanyContracts(URL);
//Do something with the result
return result;
}
EDIT
оригинальный ответ используется DownloadStringAsync который является унаследованным методом, который вызывает событие, когда загрузка завершится. Правильный метод DownloadStringTaskAsync
EDIT 2 Поскольку мы говорим о UI, код может быть асинхронными весь путь к началу обработчика событий, используя синтаксис async void
для обработчика, например async void Button1_Click
, например:
async void LoadCustomers_Click(...)
{
var contracts=await LoaCompanyContracts(_companyUrls);
txtContracts>Text=contracts;
}
в этом случае мы хотим , чтобы вернуться к исходной теме, поэтому мы не используем ConfigureAwait(false);
'result.Result' this blocks –
Это неправильный способ использования' async' и Task.Result. –
Интересно, что сам компилятор даст вам предупреждение, в котором говорится, что 'LoadCompanyContracts' будет работать синхронно. –