HttpClient와 WebClient 사이에서 결정


218

우리의 웹 응용 프로그램은 .Net Framework 4.0에서 실행됩니다. UI는 아약스 호출을 통해 컨트롤러 메소드를 호출합니다.

공급 업체의 REST 서비스를 사용해야합니다. .Net 4.0에서 REST 서비스를 호출하는 가장 좋은 방법을 평가하고 있습니다. REST 서비스에는 기본 인증 체계가 필요하며 XML과 JSON으로 데이터를 리턴 할 수 있습니다. 대용량 데이터를 업로드 / 다운로드 할 필요가 없으며 앞으로는 아무것도 보이지 않습니다. REST 소비를위한 오픈 소스 코드 프로젝트를 몇 가지 살펴 보았고 프로젝트의 추가 종속성을 정당화 할 가치가 없었습니다. 평가하기 시작 WebClient하고 HttpClient. NuGet에서 .Net 4.0 용 HttpClient를 다운로드했습니다.

나는 차이를 검색 WebClient하고 HttpClient그리고 이 사이트는 그 하나의 HttpClient를 처리 할 수있는 동시 통화를 언급하며 DNS, 쿠키 설정 및 인증을 해결 재사용 할 수 있습니다. 차이로 인해 얻을 수있는 실질적인 가치를 아직 보지 못했습니다.

WebClient(동기 호출), HttpClient(동기 및 비동기) 수행 방법을 찾기 위해 빠른 성능 테스트를 수행했습니다. 결과는 다음과 같습니다.

HttpClient모든 요청에 동일한 인스턴스 사용 (최소-최대)

WebClient 동기화 : 8ms -167ms
HttpClient 동기화 : 3ms
-7228ms HttpClient 비동기 : 985-10405ms

HttpClient각 요청에 새로운 사용 (최소-최대)

WebClient 동기화 :
4ms-297ms HttpClient 동기화 : 3ms-7953ms
HttpClient 비동기 : 1027-10834ms

암호

public class AHNData
{
    public int i;
    public string str;
}

public class Program
{
    public static HttpClient httpClient = new HttpClient();
    private static readonly string _url = "http://localhost:9000/api/values/";

    public static void Main(string[] args)
    {
       #region "Trace"
       Trace.Listeners.Clear();

       TextWriterTraceListener twtl = new TextWriterTraceListener(
           "C:\\Temp\\REST_Test.txt");
       twtl.Name = "TextLogger";
       twtl.TraceOutputOptions = TraceOptions.ThreadId | TraceOptions.DateTime;

       ConsoleTraceListener ctl = new ConsoleTraceListener(false);
       ctl.TraceOutputOptions = TraceOptions.DateTime;

       Trace.Listeners.Add(twtl);
       Trace.Listeners.Add(ctl);
       Trace.AutoFlush = true;
       #endregion

       int batchSize = 1000;

       ParallelOptions parallelOptions = new ParallelOptions();
       parallelOptions.MaxDegreeOfParallelism = batchSize;

       ServicePointManager.DefaultConnectionLimit = 1000000;

       Parallel.For(0, batchSize, parallelOptions,
           j =>
           {
               Stopwatch sw1 = Stopwatch.StartNew();
               GetDataFromHttpClientAsync<List<AHNData>>(sw1);
           });
       Parallel.For(0, batchSize, parallelOptions,
            j =>
            {
                Stopwatch sw1 = Stopwatch.StartNew();
                GetDataFromHttpClientSync<List<AHNData>>(sw1);
            });
       Parallel.For(0, batchSize, parallelOptions,
            j =>
            {
                using (WebClient client = new WebClient())
                {
                   Stopwatch sw = Stopwatch.StartNew();
                   byte[] arr = client.DownloadData(_url);
                   sw.Stop();

                   Trace.WriteLine("WebClient Sync " + sw.ElapsedMilliseconds);
                }
           });

           Console.Read();
        }

        public static T GetDataFromWebClient<T>()
        {
            using (var webClient = new WebClient())
            {
                webClient.BaseAddress = _url;
                return JsonConvert.DeserializeObject<T>(
                    webClient.DownloadString(_url));
            }
        }

        public static void GetDataFromHttpClientSync<T>(Stopwatch sw)
        {
            HttpClient httpClient = new HttpClient();
            var response = httpClient.GetAsync(_url).Result;
            var obj = JsonConvert.DeserializeObject<T>(
                response.Content.ReadAsStringAsync().Result);
            sw.Stop();

            Trace.WriteLine("HttpClient Sync " + sw.ElapsedMilliseconds);
        }

        public static void GetDataFromHttpClientAsync<T>(Stopwatch sw)
        {
           HttpClient httpClient = new HttpClient();
           var response = httpClient.GetAsync(_url).ContinueWith(
              (a) => {
                 JsonConvert.DeserializeObject<T>(
                    a.Result.Content.ReadAsStringAsync().Result);
                 sw.Stop();
                 Trace.WriteLine("HttpClient Async " + sw.ElapsedMilliseconds);
              }, TaskContinuationOptions.None);
        }
    }
}

내 질문

  1. REST 호출은 3-4로 리턴되며 이는 허용됩니다. REST 서비스에 대한 호출은 ajax 호출에서 호출되는 컨트롤러 메소드에서 시작됩니다. 우선, 호출은 다른 스레드에서 실행되며 UI를 차단하지 않습니다. 동기화 호출을 계속 사용할 수 있습니까?
  2. 위의 코드는 내 로컬 박스에서 실행되었습니다. 제품 설정에서는 DNS 및 프록시 조회가 포함됩니다. HttpClientover 를 사용하면 어떤 이점이 WebClient있습니까?
  3. HttpClient동시성보다 더 WebClient? 테스트 결과 WebClient동기화 호출이 더 잘 수행되는 것을 알 수 있습니다.
  4. HttpClient우리가 닷넷 4.5로 업그레이드하는 경우 더 나은 디자인 선택? 성능은 핵심 설계 요소입니다.

5
테스트는 GetDataFromHttpClientAsync먼저 실행되기 때문에 불공평하며 , 다른 호출은 잠재적으로 cahed 데이터 (로컬 시스템 또는 사용자와 대상 사이의 투명한 프록시 등)를 갖는 이점을 얻습니다. 또한 올바른 조건 var response = httpClient.GetAsync("http://localhost:9000/api/values/").Result;에서 스레드 풀 스레드가 소진되어 교착 상태 가 발생할 수 있습니다. ThreadPool 스레드의 스레드 풀에 의존하는 활동을 차단해서는 안되며 await대신 스레드를 풀로 다시 리턴 해야 합니다.
Scott Chamberlain

1
Web API Client가 포함 된 HttpClient는 JSON / XML REST 클라이언트에 적합합니다.
Cory Nelson

@Scott Chamberlain-답장을 보내 주셔서 감사합니다. 모든 테스트 호출이 Parallel.Foreach에서 실행되므로 어느 테스트 호출이 먼저 실행되는지 보장 할 수 없습니다. 또한 서비스에 대한 첫 번째 호출이 GetDataFromHttpClientAsync에서 호출 된 경우 GetDataFromHttpClientAsync의 모든 후속 호출에서 캐시의 이점을 얻고 더 빠르게 실행해야합니다. 결과에서 그것을 보지 못했습니다. Rgd는 아직 4.0을 사용하고 있습니다. 동기화 방식으로 HttpClient가 교착 상태로 이어질 수 있다는 점에 동의하며 디자인 고려 사항에서 해당 옵션을 결정합니다.
user3092913

@CoryNelson Web API Client를 사용하는 HttpClient가 JSON / XML REST 클라이언트에 환상적인 이유를 자세히 설명해 주시겠습니까?
user3092913

2
다음은 HttpClient를와 웹 클라이언트 사이의 차이에 몇 단어 blogs.msdn.com/b/henrikn/archive/2012/02/11/...
JustAndrei

답변:


243

나는 F #과 Web API 세계에 살고 있습니다.

웹 API에는 특히 보안을위한 메시지 처리기 등의 많은 좋은 일들이 있습니다.

나는 내 의견이 단 하나의 의견이라는 것을 알고 있지만 앞으로의 작업에 사용하는 것이 좋습니다HttpClient . 어쩌면 System.Net.Http그 어셈블리를 직접 사용하지 않고 나오는 다른 조각을 활용할 수있는 방법이있을 수 있지만 현재로서는 어떻게 작동하는지 상상할 수 없습니다.

이 두 가지를 비교하면

  • HttpClient는 WebClient보다 HTTP에 더 가깝습니다.
  • HttpClient는 보고서 진행, 사용자 지정 URI 체계 및 WebClient가 제공하는 FTP 호출과 같은 것들이 있지만 HttpClient는 그렇지 않기 때문에 Web Client를 완전히 대체하기위한 것이 아닙니다.
+--------------------------------------------+--------------------------------------------+
|               WebClient                    |               HttpClient                   |
+--------------------------------------------+--------------------------------------------+
| Available in older versions of .NET        | .NET 4.5 only.  Created to support the     |
|                                            | growing need of the Web API REST calls     |
+--------------------------------------------+--------------------------------------------+
| WinRT applications cannot use WebClient    | HTTPClient can be used with WinRT          |
+--------------------------------------------+--------------------------------------------+
| Provides progress reporting for downloads  | No progress reporting for downloads        |
+--------------------------------------------+--------------------------------------------+
| Does not reuse resolved DNS,               | Can reuse resolved DNS, cookie             |
| configured cookies                         | configuration and other authentication     |
+--------------------------------------------+--------------------------------------------+
| You need to new up a WebClient to          | Single HttpClient can make concurrent      |
| make concurrent requests.                  | requests                                   |
+--------------------------------------------+--------------------------------------------+
| Thin layer over WebRequest and             | Thin layer of HttpWebRequest and           |
| WebResponse                                | HttpWebResponse                            |
+--------------------------------------------+--------------------------------------------+
| Mocking and testing WebClient is difficult | Mocking and testing HttpClient is easy     |
+--------------------------------------------+--------------------------------------------+
| Supports FTP                               | No support for FTP                         |
+--------------------------------------------+--------------------------------------------+
| Both Synchronous and Asynchronous methods  | All IO bound methods in                    |
| are available for IO bound requests        | HTTPClient are asynchronous                |
+--------------------------------------------+--------------------------------------------+

.NET 4.5를 사용하는 경우 Microsoft가 개발자에게 제공하는 HttpClient에서 비동기 기능을 사용하십시오. HttpClient는 HttpRequest 및 HttpResponse와 같은 HTTP의 서버 측 형제와 매우 대칭입니다.

업데이트 : 새로운 HttpClient API를 사용해야하는 5 가지 이유 :

  • 강력하게 입력 된 헤더.
  • 공유 캐시, 쿠키 및 자격 증명
  • 쿠키 및 공유 쿠키에 액세스
  • 캐싱 및 공유 캐시를 제어합니다.
  • 코드 모듈을 ASP.NET 파이프 라인에 삽입하십시오. 보다 깨끗하고 모듈화 된 코드.

참고

C # 5.0 조셉 알바 하리

(채널 9 — 비디오 제작 2013)

새로운 HttpClient API를 사용하여 웹 서비스에 연결해야하는 5 가지 이유

WebClient 대 HttpClient 대 HttpWebRequest


4
HttpClient는 .NET 4.0 에서도 사용할 수 있습니다.
Todd Menier

2
이것은 왜 WebClient가 HttpClient보다 더 빠른 것으로 보이는지 설명하지 않습니다. 또한 WebClient비동기 메소드가있는 것 같습니다.
호감

8
OP는 OP가 모든 단일 요청에 대해 HttpClient의 새 인스턴스를 생성하기 때문입니다. 대신 애플리케이션 수명 동안 HttpClient의 단일 인스턴스를 사용해야합니다.
Gabriel

6
주목할 그것은의 가치가 WebClient에서 사용할 수 없습니다 .Net CoreHttpClient입니다.
Pranav Singh

3
.Net Core 2.0 WebClient (수천 개의 다른 API 중)가 제공되어 사용 가능합니다.
CoderBang

56

HttpClient는 최신 API이며 다음과 같은 이점이 있습니다.

  • 좋은 비동기 프로그래밍 모델이 있습니다
  • 기본적으로 HTTP 발명자 중 한 명인 Henrik F Nielson이 작업 중이며 API를 설계하여 표준 규격 헤더 생성과 같은 HTTP 표준을 쉽게 따르도록합니다.
  • .Net framework 4.5에 있으므로, 예측 가능한 미래에 대해 어느 정도 보장 된 수준의 지원을 제공합니다
  • .Net 4.0, Windows Phone 등의 다른 플랫폼에서 사용하려는 경우 xcopyable / portable-framework 버전의 라이브러리도 있습니다.

다른 웹 서비스에 대해 REST 호출을 수행하는 웹 서비스를 작성중인 경우 모든 REST 호출에 대해 비동기 프로그래밍 모델을 사용하여 스레드 기아 상태에 도달하지 않아야합니다. 비동기 / 대기 지원 기능이있는 최신 C # 컴파일러를 사용하고 싶을 수도 있습니다.

참고 : 성능이 뛰어난 AFAIK는 아닙니다. 공정한 테스트를 만들면 아마도 비슷한 성능을 보일 것입니다.


프록시를 전환하는 방법이 있다면
미쳤을

3

첫째, 나는 특히 WebClient 대 HttpClient의 권위자가 아닙니다. 둘째, 위의 의견에서 WebClient는 Sync ONLY이고 HttpClient는 둘 다 제안하는 것 같습니다.

WebClient (동기화 호출), HttpClient (동기화 및 비 동기화)가 수행되는 방법을 찾기 위해 빠른 성능 테스트를 수행했습니다. 결과는 다음과 같습니다.

나는 미래를 생각할 때, 즉 장기 실행 프로세스, 반응 형 GUI 등 큰 차이로 본다 (프레임 워크 4.5에서 제안한 이점에 추가하십시오-실제 경험에서 IIS에서 훨씬 빠릅니다)


4
WebClient최신 .NET 버전에서 비동기 기능이있는 것 같습니다. 왜 그렇게 거대한 규모에서 HttpClient보다 성능이 우수한 것으로 보이는지 알고 싶습니다.
호감

1
stackoverflow.com/a/4988325/1662973 에 따르면 , 하나는 다른 것의 추상화라는 사실 외에는 동일하게 보입니다. 어쩌면 객체의 사용 /로드 방법에 달려 있습니다. 최소 시간은 웹 클라이언트가 실제로 HttpClient의 추상화라는 문장을 지원하므로 밀리 초의 오버 헤드가 있습니다. 이 프레임 워크는 웹 클라이언트를 실제로 풀링하거나 폐기하는 방식에서 "비밀 한"상태 일 수 있습니다.
Anthony Horne

3

HttpClientFactory

HttpClient를 만들 수있는 다양한 방법을 평가하는 것이 중요하며 그 중 일부는 HttpClientFactory를 이해하는 것입니다.

https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests

이것은 내가 아는 직접적인 대답은 아니지만 new HttpClient(...)모든 곳에서 끝나는 것보다 여기에서 시작하는 것이 좋습니다 .


2

HttpClient, WebClient, HttpWebResponse 사이에 벤치 마크가 있고 Rest Web Api를 호출합니다.

결과 콜 레스트 웹 API 벤치 마크

--------------------- 1 단계 ---- 10 요청

{00 : 00 : 17.2232544} ====> HttpClinet

{00 : 00 : 04.3108986} ====> 웹 요청

{00 : 00 : 04.5436889} ====> 웹 클라이언트

--------------------- 1 단계 ---- 10 요청-작은 크기

{00 : 00 : 17.2232544} ====> HttpClinet

{00 : 00 : 04.3108986} ====> WebRequest

{00 : 00 : 04.5436889} ====> 웹 클라이언트

--------------------- 3 단계 ---- 10 sync 요청-작은 크기

{00 : 00 : 15.3047502} ====> HttpClinet

{00 : 00 : 03.5505249} ====> 웹 요청

{00 : 00 : 04.0761359} ====> 웹 클라이언트

--------------------- 4 단계 ---- 100 sync 요청-작은 크기

{00 : 03 : 23.6268086} ====> HttpClinet

{00 : 00 : 47.1406632} ====> WebRequest

{00 : 01 : 01.2319499} ====> 웹 클라이언트

--------------------- 단계 5 ---- 10 sync 요청-최대 크기

{00 : 00 : 58.1804677} ====> HttpClinet

{00 : 00 : 58.0710444} ====> WebRequest

{00 : 00 : 38.4170938} ====> 웹 클라이언트

--------------------- 단계 6 ---- 10 동기화 요청-최대 크기

{00 : 01 : 04.9964278} ====> HttpClinet

{00 : 00 : 59.1429764} ====> WebRequest

{00 : 00 : 32.0584836} ====> 웹 클라이언트

_____ WebClient가 빠릅니다 ()

var stopWatch = new Stopwatch();
        stopWatch.Start();
        for (var i = 0; i < 10; ++i)
        {
            CallGetHttpClient();
            CallPostHttpClient();
        }

        stopWatch.Stop();

        var httpClientValue = stopWatch.Elapsed;

        stopWatch = new Stopwatch();

        stopWatch.Start();
        for (var i = 0; i < 10; ++i)
        {
            CallGetWebRequest();
            CallPostWebRequest();
        }

        stopWatch.Stop();

        var webRequesttValue = stopWatch.Elapsed;


        stopWatch = new Stopwatch();

        stopWatch.Start();
        for (var i = 0; i < 10; ++i)
        {

            CallGetWebClient();
            CallPostWebClient();

        }

        stopWatch.Stop();

        var webClientValue = stopWatch.Elapsed;

// ------------------------- 함수

private void CallPostHttpClient()
    {
        var httpClient = new HttpClient();
        httpClient.BaseAddress = new Uri("https://localhost:44354/api/test/");
        var responseTask = httpClient.PostAsync("PostJson", null);
        responseTask.Wait();

        var result = responseTask.Result;
        var readTask = result.Content.ReadAsStringAsync().Result;

    }
    private void CallGetHttpClient()
    {
        var httpClient = new HttpClient();
        httpClient.BaseAddress = new Uri("https://localhost:44354/api/test/");
        var responseTask = httpClient.GetAsync("getjson");
        responseTask.Wait();

        var result = responseTask.Result;
        var readTask = result.Content.ReadAsStringAsync().Result;

    }
    private string CallGetWebRequest()
    {
        var request = (HttpWebRequest)WebRequest.Create("https://localhost:44354/api/test/getjson");

        request.Method = "GET";
        request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;

        var content = string.Empty;

        using (var response = (HttpWebResponse)request.GetResponse())
        {
            using (var stream = response.GetResponseStream())
            {
                using (var sr = new StreamReader(stream))
                {
                    content = sr.ReadToEnd();
                }
            }
        }

        return content;
    }
    private string CallPostWebRequest()
    {

        var apiUrl = "https://localhost:44354/api/test/PostJson";


        HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(new Uri(apiUrl));
        httpRequest.ContentType = "application/json";
        httpRequest.Method = "POST";
        httpRequest.ContentLength = 0;

        using (var httpResponse = (HttpWebResponse)httpRequest.GetResponse())
        {
            using (Stream stream = httpResponse.GetResponseStream())
            {
                var json = new StreamReader(stream).ReadToEnd();
                return json;
            }
        }

        return "";
    }

    private string CallGetWebClient()
    {
        string apiUrl = "https://localhost:44354/api/test/getjson";


        var client = new WebClient();

        client.Headers["Content-type"] = "application/json";

        client.Encoding = Encoding.UTF8;

        var json = client.DownloadString(apiUrl);


        return json;
    }

    private string CallPostWebClient()
    {
        string apiUrl = "https://localhost:44354/api/test/PostJson";


        var client = new WebClient();

        client.Headers["Content-type"] = "application/json";

        client.Encoding = Encoding.UTF8;

        var json = client.UploadString(apiUrl, "");


        return json;
    }

1
위의 가브리엘의 의견을보십시오. 간단히 말해서 HttpClient의 인스턴스 하나를 만들어 재사용하면 HttpClient가 훨씬 빠릅니다.
LT Dan

1

아마도 당신은 다른 방식으로 문제에 대해 생각할 수 있습니다. WebClientHttpClient같은 것을 본질적으로 다른 구현이다. 권장 사항은 응용 프로그램 전체 에서 IoC 컨테이너로 Dependency Injection 패턴 을 구현하는 것 입니다. 저수준 HTTP 전송보다 추상화 수준이 높은 클라이언트 인터페이스를 구성해야합니다. 당신은 모두를 사용하여 구체적인 클래스를 쓸 수 있습니다 및 다음 설정을 통해 구현을 주입하는 IoC 컨테이너를 사용합니다.WebClientHttpClient

이것이 당신이 할 수있는 것입니다 것은 사이를 전환하는 것 HttpClient하고 WebClient쉽게 그래서 당신은 프로덕션 환경에서 객관적으로 테스트 할 수 있음.

따라서 다음과 같은 질문이 있습니다.

.Net 4.5로 업그레이드하면 HttpClient가 더 나은 디자인 선택입니까?

실제로 IoC 컨테이너를 사용하여 두 클라이언트 구현간에 전환하여 객관적으로 답변 할 수 있습니다. 다음은 HttpClientor에 대한 세부 정보가 포함되지 않은 인터페이스 예 WebClient입니다.

/// <summary>
/// Dependency Injection abstraction for rest clients. 
/// </summary>
public interface IClient
{
    /// <summary>
    /// Adapter for serialization/deserialization of http body data
    /// </summary>
    ISerializationAdapter SerializationAdapter { get; }

    /// <summary>
    /// Sends a strongly typed request to the server and waits for a strongly typed response
    /// </summary>
    /// <typeparam name="TResponseBody">The expected type of the response body</typeparam>
    /// <typeparam name="TRequestBody">The type of the request body if specified</typeparam>
    /// <param name="request">The request that will be translated to a http request</param>
    /// <returns></returns>
    Task<Response<TResponseBody>> SendAsync<TResponseBody, TRequestBody>(Request<TRequestBody> request);

    /// <summary>
    /// Default headers to be sent with http requests
    /// </summary>
    IHeadersCollection DefaultRequestHeaders { get; }

    /// <summary>
    /// Default timeout for http requests
    /// </summary>
    TimeSpan Timeout { get; set; }

    /// <summary>
    /// Base Uri for the client. Any resources specified on requests will be relative to this.
    /// </summary>
    Uri BaseUri { get; set; }

    /// <summary>
    /// Name of the client
    /// </summary>
    string Name { get; }
}

public class Request<TRequestBody>
{
    #region Public Properties
    public IHeadersCollection Headers { get; }
    public Uri Resource { get; set; }
    public HttpRequestMethod HttpRequestMethod { get; set; }
    public TRequestBody Body { get; set; }
    public CancellationToken CancellationToken { get; set; }
    public string CustomHttpRequestMethod { get; set; }
    #endregion

    public Request(Uri resource,
        TRequestBody body,
        IHeadersCollection headers,
        HttpRequestMethod httpRequestMethod,
        IClient client,
        CancellationToken cancellationToken)
    {
        Body = body;
        Headers = headers;
        Resource = resource;
        HttpRequestMethod = httpRequestMethod;
        CancellationToken = cancellationToken;

        if (Headers == null) Headers = new RequestHeadersCollection();

        var defaultRequestHeaders = client?.DefaultRequestHeaders;
        if (defaultRequestHeaders == null) return;

        foreach (var kvp in defaultRequestHeaders)
        {
            Headers.Add(kvp);
        }
    }
}

public abstract class Response<TResponseBody> : Response
{
    #region Public Properties
    public virtual TResponseBody Body { get; }

    #endregion

    #region Constructors
    /// <summary>
    /// Only used for mocking or other inheritance
    /// </summary>
    protected Response() : base()
    {
    }

    protected Response(
    IHeadersCollection headersCollection,
    int statusCode,
    HttpRequestMethod httpRequestMethod,
    byte[] responseData,
    TResponseBody body,
    Uri requestUri
    ) : base(
        headersCollection,
        statusCode,
        httpRequestMethod,
        responseData,
        requestUri)
    {
        Body = body;
    }

    public static implicit operator TResponseBody(Response<TResponseBody> readResult)
    {
        return readResult.Body;
    }
    #endregion
}

public abstract class Response
{
    #region Fields
    private readonly byte[] _responseData;
    #endregion

    #region Public Properties
    public virtual int StatusCode { get; }
    public virtual IHeadersCollection Headers { get; }
    public virtual HttpRequestMethod HttpRequestMethod { get; }
    public abstract bool IsSuccess { get; }
    public virtual Uri RequestUri { get; }
    #endregion

    #region Constructor
    /// <summary>
    /// Only used for mocking or other inheritance
    /// </summary>
    protected Response()
    {
    }

    protected Response
    (
    IHeadersCollection headersCollection,
    int statusCode,
    HttpRequestMethod httpRequestMethod,
    byte[] responseData,
    Uri requestUri
    )
    {
        StatusCode = statusCode;
        Headers = headersCollection;
        HttpRequestMethod = httpRequestMethod;
        RequestUri = requestUri;
        _responseData = responseData;
    }
    #endregion

    #region Public Methods
    public virtual byte[] GetResponseData()
    {
        return _responseData;
    }
    #endregion
}

전체 코드

HttpClient 구현

구현에서 비동기 적으로 실행 Task.Run하는 데 사용할 수 있습니다 WebClient.

Dependency Injection은 잘 수행되면 낮은 수준의 의사 결정을 미리 내릴 때 발생하는 문제를 완화하는 데 도움이됩니다. 궁극적으로 정답을 알 수있는 유일한 방법은 실제 환경에서 가장 효과적인 방법을 확인하는 것입니다. 그것은 그 꽤 가능성이 WebClient일부 고객을 위해 더 잘 작동 할 수 있으며, HttpClient다른 사람을 위해 잘 작동 할 수 있습니다. 이것이 추상화가 중요한 이유입니다. 즉, 앱의 기본 디자인을 변경하지 않고도 코드를 신속하게 교체하거나 구성으로 변경할 수 있습니다.


1

2020 년의 인기없는 의견 :

ASP.NET 앱과 관련 하여 다음 WebClient과 같은 HttpClient이유로 여전히 선호합니다 .

  1. 최신 구현에는 비동기 / 대기 가능한 작업 기반 방법이 제공됩니다.
  2. 더 작은 메모리 공간과 2x-5x 더 빠름 (다른 답변은 이미 언급했습니다)
  3. " 응용 프로그램 수명 동안 HttpClient의 단일 인스턴스를 재사용하는 것이 좋습니다 ". 그러나 ASP.NET에는 "응용 프로그램 수명"이 없으며 요청 수명 만 있습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.