Подтвердить что ты не робот

Лучший способ использовать приятный .net 4.5 HttpClient синхронно

Мне нравится новый класс System.Net.Http.HttpClient. У этого есть хороший простой API, он не бросает на обычные ошибки. Но его асинхронно.

Мне нужен код, который идет (глубоко внутри сервера)

foo();
bar();
// compute stuff
var x = GetThingFromOtherServerViaHttp();
// compute more stuff
wiz(x);

классический последовательный синхронный код. Я видел несколько вопросов SO, которые были похожи, но на самом деле не заканчивали тем, что говорили "сделай это". Я посмотрел на

client.PostAsync.Wait()

Мировые крики "не делают этого". Как насчет:

client.PostAsync.Result()

Разве это не просто переодеться?

В конце концов я закончил тем, что передал обратный вызов лямбда, который обработал результат, а затем пробудил вызывающий поток, который явно ожидал события EventWaitHandle. Много сантехники. Есть ли что-то немного проще или shoul, я просто возвращаюсь к использованию старых http-клиентов.

EDIT: после дальнейшего чтения я подозреваю, что этот код имеет те же проблемы, что и Wait и Result, его просто более длинный тупик

EDIT: Недавно я получил сообщение MS PM о том, что существует мандат "любой API, который может принимать > X ms (я забыл X) должен быть асинхронным", многие PM интерпретируют это как "только async" (неясно, если это то, что предназначено). Следовательно, DB DB документа является только асинхронным.

4b9b3361

Ответ 2

@Noseratio - конечно, меня беспокоят тупики: -)

Вы будете беспокоиться только о блокировках , если вы находитесь в потоке с контекстом синхронизации.

Обычно это будет либо основной поток приложения UI (на стороне клиента), либо случайный поток ASP.NET, обрабатывающий HTTP-запрос (на стороне сервера). В любом случае вы действительно не должны его блокировать.

Принятый ответ может помочь смягчить тупик, но блокировка, подобная этому, все равно повредит пользовательскому интерфейсу вашего пользовательского интерфейса (пользовательский интерфейс будет заморожен) или масштабируемость приложения на стороне сервера (поток, потраченный на блокирование, в то время как он может обслуживать другой запрос). Просто не блокируйте и не используйте async/await до конца.

Вы упомянули "глубоко внутри сервера", но не указали никаких подробностей о том, что такое серверное приложение. Большинство современных серверных фреймворков имеют хорошую настройку для async/await, поэтому это не должно быть проблемой, охватывающей его.

Обновлено, чтобы ответить на комментарий:

Мне все еще не нравится тот факт, что тот же код написан на разных места будут заторможены. Я ожидал бы, что вызов ожидания в тупиковой ситуации среда, чтобы бросить

Это не является особой проблемой async/await, а является концепцией контекста синхронизации в целом, когда она используется с блокирующим кодом. Вот тупик в двух словах:

private void Form1_Load(object sender, EventArgs e)
{
    var mre = new System.Threading.ManualResetEvent(initialState: false);
    System.Threading.SynchronizationContext.Current.Post(_ => 
        mre.Set(), null);
    mre.WaitOne();
    MessageBox.Show("We never get here");
}

В теории можно было бы попытаться смягчить возможные взаимоблокировки внутри SynchronizationContext.Post, скажем, путем проверки Thread.ThreadState == System.Threading.ThreadState.WaitSleepJoin. Это, однако, не будет на 100% надежным решением.

Ответ 3

Спорно я собираюсь сказать System.Net.Http.HttpClient вы , вероятно, может просто использовать .Result

Microsoft должна была следовать своим советам и использовать .ConfigureAwait(false) всю дорогу в этой библиотеке. Источник ссылки подразумевает следующее:

https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/System/Net/Http/HttpClient.cs

Зачем рисковать? Потому что он должен быть немного более легким, чем Task.Run(() => Client.PostAsync()).Result.

Я бы не стал доверять многим (каким-нибудь?) другим библиотекам, которые должны быть закодированы безопасно, и с нетерпением ждем, если кто-нибудь возразит против моего ответа или еще лучше, но докажет, что я ошибаюсь.