同期接続にHttpClientを使用する理由


187

APIと対話するためのクラスライブラリを構築しています。APIを呼び出してXML応答を処理する必要があります。HttpClient非同期接続に使用することの利点はわかりますが、私がしていることは純粋に同期であるため、を使用することよりも大きな利点はありませんHttpWebRequest

誰かが光を当てることができれば私はそれを大いに感謝します。私はそれのために新しいテクノロジーを使用するためのものではありません。


3
言いたくないのですが、Windowsネットワークが内部でどのように機能するか(つまり、完了ポート)のため、HTTP経由の呼び出しは純粋に同期になることはありません。
TomTom 2016年


また、知っておくと
RBT

回答:


370

しかし、私がやっていることは純粋に同期です

HttpClient同期リクエストにうまく使用できます:

using (var client = new HttpClient())
{
    var response = client.GetAsync("http://google.com").Result;

    if (response.IsSuccessStatusCode)
    {
        var responseContent = response.Content; 

        // by calling .Result you are synchronously reading the result
        string responseString = responseContent.ReadAsStringAsync().Result;

        Console.WriteLine(responseString);
    }
}

なぜHttpClientオーバーを使用する必要があるかということWebRequestに関しては、まあ、HttpClientブロックの新しい子供であり、古いクライアントに対する改善を含めることができます。


27
非同期メソッドを同期的に使用すると、UIスレッドがブロックされる可能性はありませんか?これを同期させる必要があるstring responseString = Task.Run(() => responseContent.ReadAsStringAsync()).Result;場合は、代わりに何かを検討する必要あります。
地球人

13
はい、@ earthling Task.RunはThreadPoolからタスクを呼び出しますが、これを呼び出して.Result、これによるすべての利点を殺し、これを呼び出したスレッド.Result(通常、メインのUIスレッド)をブロックします。
Darin Dimitrov

35
この投稿(blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx)によると、この.Resultような呼び出しはスレッドプールを使い果たし、デッドロックを引き起こす可能性があります。
ピートガラファノ2014

16
メインUIスレッド上で作成したタスク内で実行される場合には、このコードは常にデッドロックしますnew TaskFactory(TaskScheduler.FromCurrentSynchronizationContext()
ヴィム・クーネン

23
では、UIスレッドからHttpClientを同期的に使用するにはどうすればよいですか?のは、私が言ってみましょう故意にデッドロックが発生する可能性がありますなど、)UIスレッドをブロックしたい(または私はコンソールアプリケーションを書いています)私は、HTTPレスポンスを得るまで...だから、もし待ち()、(結果、これに対する明確な解決策は何ですかなしデッドロックのリスクとWebClientのような他のクラス使用せずに
デクスター

26

私はドニーV.の回答とジョシュの

「非同期バージョンを使用しない唯一の理由は、非同期サポートが組み込まれていない古いバージョンの.NETをサポートしようとした場合です。」

(そして私が評判を持っている場合は賛成票を投じます。)

前回のことは思い出せませんが、HttpWebRequestがステータスコード> = 400の例外をスローしたという事実に感謝しました。これらの問題を回避するには、例外をすぐにキャッチし、例外以外の応答メカニズムにマッピングする必要がありますあなたのコードでは...退屈で退屈でエラーが発生しやすいです。データベースと通信する場合でも、カスタムのWebプロキシを実装する場合でも、Httpドライバーがアプリケーションコードに返されたものを通知し、動作方法を決定するのはユーザーに任せるのが常に「ほぼ」望ましいことです。

したがって、HttpClientが推奨されます。


1
HttpClientそれ自体がラッパーであることに驚きましたHttpWebRequest(実際、内部的にこれらのWebExceptionオブジェクトをキャッチし、変換をHttpResponseMessage行います)。新しいクライアントを完全にゼロから構築する方が簡単だと思いました。

3
パフォーマンスさえ重要ではない非常に低レベルのhttp呼び出しのためだけにコードベース全体を書き直したくないなど、十分な理由があります(ただし、100万の場所に非同期を導入します)。
FrankyBoy 2018年

.netコア2では、DynamicExpressionParserを使用して式を動的に評価する場合、asyncを使用できない場合があります。プロパティインデクサーは非同期を使用できません。私の状況で、私はこの方法がHttpCallとインデックスの構文を作る「GetDefaultWelcomeMessage [\」InitialMessage \「]」のような文字列は、メソッドの構文に好適である動的に評価する必要がある「Util.GetDefaultWelcomeMessage(\」InitialMessage \「)」
オイゲン

7

クラスライブラリを構築している場合、おそらくライブラリのユーザーはライブラリを非同期で使用したいと思うでしょう。それが最大の理由だと思います。

また、ライブラリの使用方法もわかりません。おそらく、ユーザーは大量のリクエストを処理し、非同期で処理することで、より高速かつ効率的に実行できます。

簡単にできる場合は、ライブラリのユーザーがフローを非同期にしようとするときに、ユーザーの負担を軽減できるようにしてください。

非同期バージョンを使用しない唯一の理由は、非同期サポートが組み込まれていない古いバージョンの.NETをサポートしようとした場合です。


わかりましたので、クラスライブラリを非同期にし、システムのユーザーが非同期で使用するか、待機して同期で使用するかを決定できるようにしますか?
ケチャップ2013年

erm、awaitは、呼び出し元に制御を返すことにより、特定の呼び出しを非同期にするのに役立ちます。
Josh Smeaton 2013年

6

私の場合、受け入れられた答えはうまくいきませんでした。非同期アクションのないMVCアプリケーションからAPIを呼び出していました。

これが私がそれをうまく機能させる方法でした:

private static readonly TaskFactory _myTaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);
public static T RunSync<T>(Func<Task<T>> func)
    {           
        CultureInfo cultureUi = CultureInfo.CurrentUICulture;
        CultureInfo culture = CultureInfo.CurrentCulture;
        return _myTaskFactory.StartNew<Task<T>>(delegate
        {
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = cultureUi;
            return func();
        }).Unwrap<T>().GetAwaiter().GetResult();
    }

次に、次のように呼び出しました。

Helper.RunSync(new Func<Task<ReturnTypeGoesHere>>(async () => await AsyncCallGoesHere(myparameter)));

1
Thx @Darkonekt ...これは私にとって完璧に機能します。HttpClient.SendAsync(...)。ResultのみがAspNetハンドラー(.ASHX)内で機能しません。
Rafael Kazuo Sato Simiao 2018年

3
public static class AsyncHelper  
{
    private static readonly TaskFactory _taskFactory = new
        TaskFactory(CancellationToken.None,
                    TaskCreationOptions.None,
                    TaskContinuationOptions.None,
                    TaskScheduler.Default);

    public static TResult RunSync<TResult>(Func<Task<TResult>> func)
        => _taskFactory
            .StartNew(func)
            .Unwrap()
            .GetAwaiter()
            .GetResult();

    public static void RunSync(Func<Task> func)
        => _taskFactory
            .StartNew(func)
            .Unwrap()
            .GetAwaiter()
            .GetResult();
}

その後

AsyncHelper.RunSync(() => DoAsyncStuff());

そのクラスを使用して、非同期メソッドをパラメーターとして渡すと、安全な方法で同期メソッドから非同期メソッドを呼び出すことができます。

ここで説明されています:https : //cpratt.co/async-tips-tricks/


-1

すべての回答はHttpClient、質問に実際に回答するのではなく、同期して使用することに焦点を当てているようです。

HttpClientこれは単純な要求/応答ハンドラ以上のものなので、さまざまなネットワークのいくつかの特殊性に対処できます。つまり、私の場合、ネゴシエーションを必要とするNTLMプロキシで作業し、認証のためにクライアントとプロキシサーバー間でトークンと資格情報を含む複数の要求/応答を送信します。HttpClient(を使用HttpClientHandler)には、1つのメソッド呼び出しでプロキシを超えてリソースを返す処理メカニズムが組み込まれているようです。


答えは、HttpClientを非同期で使用する方法も説明していません。
user275801

@ user275801ばかげたコメントです。誰もそれを尋ねませんでした。デフォルトでは非同期です。
Bizniztime
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.