동기 연결에 HttpClient를 사용하는 이유


188

API와 상호 작용할 클래스 라이브러리를 작성 중입니다. API를 호출하고 XML 응답을 처리해야합니다. HttpClient비동기 연결 에 사용하면 얻을 수있는 이점을 볼 수 있지만 내가하는 일은 순전히 동기이므로를 사용하는 것보다 큰 이점을 볼 수 없습니다 HttpWebRequest.

누구든지 어떤 빛을 발산 할 수 있다면 크게 감사하겠습니다. 나는 그것을 위해 새로운 기술을 사용하는 사람이 아닙니다.


3
나는 당신에게 말하기를 싫어하지만, Windows 네트워킹이 내부적으로 작동하는 방식 (일명 완성 포트)으로 인해 HTTP를 통한 호출은 절대로 동기식이 아닙니다.
TomTom


답변:


374

하지만 내가하고있는 일은 순전히 동기입니다

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;대신하는 경우 합니다 이 동기하게합니다.
earthling

13
@earthling, yes Task.Run는 ThreadPool에서 작업을 호출하지만, .Result이것으로 모든 이점을 없애고 호출 한 스레드 .Result(일반적으로 기본 UI 스레드)를 차단합니다 .
Darin Dimitrov

35
이 게시물 ( blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx ) 에 따르면 이와 .Result같이 호출 하면 스레드 풀이 소모되고 교착 상태가 발생할 수 있습니다.
피트 가라 파노

16
이 코드는 기본 UI 스레드에서 생성 된 작업 내에서 실행되는 경우 항상 교착 상태가 발생합니다.new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext()
Wim Coenen

24
그렇다면 UI 스레드에서 HttpClient를 어떻게 동 기적으로 사용합니까? 하자 내가 말을 의도적으로 (또는 내가 콘솔 응용 프로그램을 쓰고 있어요) 나는 HTTP 응답을 얻을 때까지 등 대기 (), 결과는 (), 교착 상태를 일으킬 수있는 경우에 ... 그래서이,이에 대한 명확한 솔루션 무엇 UI 스레드를 차단하려는 없이 교착 상태의 위험이 있으며 WebClient와 같은 다른 클래스 사용 하지 않습니까?
Dexter

26

Donny V. 답변과 Josh 's를 다시 반복하겠습니다.

"비동기 버전을 사용하지 않는 유일한 이유는 이미 비동기 지원 기능이 내장되어 있지 않은 이전 버전의 .NET을 지원하려고했기 때문입니다."

(그리고 평판이 있다면 공감하십시오.)

HttpWebRequest가 상태 코드> = 400에 대해 예외를 발생시킨 사실에 대해 마지막으로 기억할 수 없었습니다. 이러한 문제를 해결하려면 예외를 즉시 포착하고 예외가 아닌 응답 메커니즘에 매핑해야합니다. 코드에서 ... 지루하고 지루하며 오류가 발생하기 쉽습니다. 데이터베이스와 통신하든, 맞춤형 웹 프록시를 구현하든, 항상 '거의'HTTP 드라이버는 애플리케이션 코드에 리턴 된 내용을 알려주고 동작 방식을 결정하도록하는 것이 바람직합니다.

따라서 HttpClient가 바람직합니다.


1
나는 깜짝 놀랐다 HttpClient자체가 래퍼 주위가 HttpWebRequest(실제로, 내부적으로 그 연결되는지 WebException오브젝트를하고로의 전환을하지 HttpResponseMessage당신을 위해). 처음부터 완전히 새로운 클라이언트를 만드는 것이 더 쉬울 것이라고 생각했을 것입니다.
다이

4
성능이 중요하지 않은 매우 낮은 수준의 http 호출에 대해서만 전체 코드베이스를 다시 작성하지 않는 것과 같은 많은 이유가 있습니다 (그러나 백만 개의 장소에 비동기 화가 발생합니다).
FrankyBoy

.net core 2에서 DynamicExpressionParser를 사용하여 식을 동적으로 평가하려면 비동기를 사용하지 못할 수 있습니다. 속성 인덱서는 비동기를 사용할 수 없습니다. 내 상황에 동적으로이 방법은 HttpCall 인덱스 구문은 메서드 구문 "Util.GetDefaultWelcomeMessage (\"InitialMessage \ ")"에 바람직하게 "GetDefaultWelcomeMessage [\"InitialMessage \ "]"와 같은 문자열을 평가해야
오이겐을

7

클래스 라이브러리를 작성하는 경우 라이브러리 사용자가 라이브러리를 비동기 적으로 사용하려고합니다. 이것이 바로 가장 큰 이유라고 생각합니다.

당신은 또한 당신의 라이브러리가 어떻게 사용 될지 모른다. 아마도 사용자는 많은 요청을 처리하고 비동기 적으로 수행하면 더 빠르고 효율적으로 수행하는 데 도움이 될 것입니다.

간단하게 처리 할 수 ​​있으면 라이브러리 사용자가 처리 할 수있을 때 플로우를 비 동기화하려고하는 라이브러리 사용자에게 부담을주지 마십시오.

비동기 버전을 사용하지 않는 유일한 이유는 이미 비동기 지원 기능이 내장되어 있지 않은 이전 버전의 .NET을 지원하려는 경우입니다.


클래스 라이브러리를 비동기로 만들고 시스템 사용자가 비동기를 사용할지 또는 대기를 사용하여 동 기적으로 사용할지를 결정할 수 있습니까?
케첩

erm, await는 호출자에게 제어권을 돌려 특정 호출을 비동기 적으로 만드는 데 도움이됩니다.
Josh Smeaton

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 ... 이것은 나에게 완벽하게 작동합니다. AspNet 처리기 (.ASHX) 내에서는 HttpClient.SendAsync (...). Result 만 작동하지 않습니다.
Rafael Kazuo Sato Simiao

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)에는 하나의 메서드 호출로 프록시 이외의 리소스를 반환하는 처리 메커니즘이 내장되어있는 것 같습니다.


귀하의 답변은 HttpClient를 비동기 적으로 사용하는 방법을 설명하지 않습니다.
user275801

@ user275801 멍청한 의견입니다. 아무도 묻지 않았습니다. 기본적으로 비동기입니다.
Bizniztime
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.