2008-10-14 13 views
138

어떻게 HttpWebRequest (.NET, C#)를 비동기 적으로 사용할 수 있습니까?HttpWebRequest (.NET)를 비동기 적으로 사용하는 방법?

+1

사용 :

private async Task<String> MakeRequestAsync(String url) { String responseText = await Task.Run(() => { try { HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; WebResponse response = request.GetResponse(); Stream responseStream = response.GetResponseStream(); return new StreamReader(responseStream).ReadToEnd(); } catch (Exception e) { Console.WriteLine("Error: " + e.Message); } return null; }); return responseText; } 

는 비동기 방식을 사용하려면 : 백그라운드 스레드에서 실행됩니다 Task을 시작 비동기 방법을 사용 /library/system.net.webrequest.endgetrequeststream.aspx –

+1

잠시 동안 재귀 적 스레드에 대해 의견을 제시하려고했는지 궁금합니다. –

+0

Jason이 요구하는 것을 수행하는 꽤 완벽한 예를 보려면 다음을 참조하십시오. http://stuff.seans.com/2009/01/05/using-httpwebrequest-for-asynchronous-downloads/ Sean –

답변

115

사용 HttpWebRequest.BeginGetResponse()

HttpWebRequest webRequest; 

void StartWebRequest() 
{ 
    webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), null); 
} 

void FinishWebRequest(IAsyncResult result) 
{ 
    webRequest.EndGetResponse(result); 
} 

비동기 작업이 완료되면 콜백 함수가 호출됩니다. 이 기능을 사용하려면 적어도 EndGetResponse()으로 전화해야합니다. ,

void StartWebRequest() 
{ 
    HttpWebRequest webRequest = ...; 
    webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), webRequest); 
} 

void FinishWebRequest(IAsyncResult result) 
{ 
    HttpWebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result) as HttpWebResponse; 
} 

인사말

+12

BeginGetResponse는 비동기 사용에 유용하지 않습니다. 리소스에 접속하는 동안 차단되는 것 같습니다. 네트워크 케이블의 플러그를 뽑거나 잘못된 URL을 제공 한 다음이 코드를 실행하십시오. 대신 GetResponse를 제공하는 두 번째 스레드에서 실행해야합니다. – Ash

+2

@AshleyHenderson - 샘플을 제공해 주시겠습니까? – Tohid

+0

@Tohid [여기 샘플 전체 클래스입니다] (http://stackoverflow.com/questions/12224602/a-method-for-making-http-requests-on-unity-ios/12606963#12606963) Unity3D와 함께 사용됩니다. – cregox

62

답을 고려 왜냐하면 BeginGetResponse()은 현재 스레드에서 일부 작업을 수행하기 때문입니다. documentation에서 :

BeginGetResponse 방법은이 방법이 비동기되기 전에 전체 (DNS 해상도, 프록시 탐지 및 TCP 소켓 연결, 예를 들어 ) 일부 동기 설정 작업이 필요합니다. 결과적으로 사용자 인터페이스 (UI) 스레드 에서이 메서드를 호출하면 안됩니다. 네트워크에 따라 초기 동기화 설정 작업을 완료하는 데 상당한 시간이 걸릴 수 있으므로 (네트워크 설정에 따라 최대 몇 분, ) 오류가 발생하거나 메서드 이 성공합니다.

void DoWithResponse(HttpWebRequest request, Action<HttpWebResponse> responseAction) 
{ 
    Action wrapperAction =() => 
    { 
     request.BeginGetResponse(new AsyncCallback((iar) => 
     { 
      var response = (HttpWebResponse)((HttpWebRequest)iar.AsyncState).EndGetResponse(iar); 
      responseAction(response); 
     }), request); 
    }; 
    wrapperAction.BeginInvoke(new AsyncCallback((iar) => 
    { 
     var action = (Action)iar.AsyncState; 
     action.EndInvoke(iar); 
    }), wrapperAction); 
} 

당신은 당신이 응답에 필요한 수행 할 수 있습니다

그래서이 권리를해야 할 일. 예를 들어 내가있는 BackgroundWorker를 사용하여 종료

HttpWebRequest request; 
// init your request...then: 
DoWithResponse(request, (response) => { 
    var body = new StreamReader(response.GetResponseStream()).ReadToEnd(); 
    Console.Write(body); 
}); 
+7

+1을 표시하지만 "as"키워드 대신에 캐스트를 만들 수 있음을 알리는 오류가 발생합니다. 혼동 대신 InvalidCastException이 throw됩니다. NullReferenceException –

3
public void GetResponseAsync (HttpWebRequest request, Action<HttpWebResponse> gotResponse) 
    { 
     if (request != null) { 
      request.BeginGetRequestStream ((r) => { 
       try { // there's a try/catch here because execution path is different from invokation one, exception here may cause a crash 
        HttpWebResponse response = request.EndGetResponse (r); 
        if (gotResponse != null) 
         gotResponse (response); 
       } catch (Exception x) { 
        Console.WriteLine ("Unable to get response for '" + request.RequestUri + "' Err: " + x); 
       } 
      }, null); 
     } 
    } 
57

모두 지금까지 잘못하고있다 :

HttpWebRequest webRequest; 

void StartWebRequest() 
{ 
    webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), null); 
} 

void FinishWebRequest(IAsyncResult result) 
{ 
    webRequest.EndGetResponse(result); 
} 

당신은이 같은 요청 포인터 또는 기타 객체를 보낼 수 :

+2

await를 사용하여 HttpWebRequest의 GetResponseAsync 메서드를 호출 할 수 없습니까 (함수를 비동기로 설정했다고 가정)? 나는 C#에 대해 매우 익숙해 졌기 때문에 이것은 완전히 변덕 스럽다. – Brad

+0

GetResponseAsync는 좋아 보이지만 .NET 4.5 (현재 베타)가 필요하다. – Isak

+12

예수님. 그것은 추악한 코드입니다. 비동기 코드를 읽을 수없는 이유는 무엇입니까? –

7

, 위의 방법 중 일부는, 당신의 GUI 스레드로 돌아 핸들과는 달리 확실히 비동기이며, 이해하기가 매우 쉽습니다. Unhandled exceptions in BackgroundWorker

내가 웹 클라이언트를 사용하지만, 당신이 원하는 경우 분명히 당신이 HttpWebRequest.GetResponse을 사용할 수

그들이 RunWorkerCompleted 방법에 끝으로, 예외를 처리하지만, 당신이 이것을 읽을 수 있는지 확인하는 것이 매우 쉽습니다. 가장 쉬운 방법으로

var worker = new BackgroundWorker(); 

worker.DoWork += (sender, args) => { 
    args.Result = new WebClient().DownloadString(settings.test_url); 
}; 

worker.RunWorkerCompleted += (sender, e) => { 
    if (e.Error != null) { 
     connectivityLabel.Text = "Error: " + e.Error.Message; 
    } else { 
     connectivityLabel.Text = "Connectivity OK"; 
     Log.d("result:" + e.Result); 
    } 
}; 

connectivityLabel.Text = "Testing Connectivity"; 
worker.RunWorkerAsync(); 
47

TPL에서 TaskFactory.FromAsync을 사용하는 것입니다.

: 그런 다음 위의 Task.ContinueWith 방법을 사용하여 수행 할 수있는 C# 5 컴파일러를 사용할 수없는 경우

var request = WebRequest.Create("http://www.stackoverflow.com"); 
var response = (HttpWebResponse) await Task.Factory 
    .FromAsync<WebResponse>(request.BeginGetResponse, 
          request.EndGetResponse, 
          null); 
Debug.Assert(response.StatusCode == HttpStatusCode.OK); 

: 새로운 async/await 키워드와 함께 사용하면 말 그대로 몇 줄기의 코드입니다

Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, 
            request.EndGetResponse, 
            null) 
    .ContinueWith(task => 
    { 
     var response = (HttpWebResponse) task.Result; 
     Debug.Assert(response.StatusCode == HttpStatusCode.OK); 
    }); 
+0

.NET 4 이후이 TAP 방식이 바람직합니다. MS와 유사한 예보기 - "방법 : 작업에서 EAP 패턴 줄이기"(http://msdn.microsoft.com/en-us/library/ee622454.aspx) –

+0

다른 방법보다 쉬운 방법 –

2

.이 답변 중 많은 수가 게시 된 이후로 NET이 변경되었으며 더 최신 답변을 제공해 드리고자합니다. http://msdn.microsoft.com/en-us 비동기

String response = await MakeRequestAsync("http://example.com/"); 
+0

감사합니다! 비동기식 예제를 찾으려고 노력 해왔다. 예전의 복잡한 접근법을 사용하는 예제가 많이있다. – WDUK

+0

각 응답마다 스레드를 차단하지 않습니까? 예를 들어, https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-wrap-eap-patterns-in-a-task –

+0

@PeteKirkham 백그라운드 스레드가 요청을 처리하고 있지만 UI 스레드. 목표는 UI 스레드를 차단하지 않는 것입니다. 요청하는 모든 메소드는 요청을 작성한 스레드를 차단합니다. 참조하는 Microsoft 예제는 여러 요청을 시도하지만 요청에 대한 Task (배경 스레드)를 작성 중입니다. – tronman

관련 문제