문제

httpwebrequest (.net, c#)를 비동기 적으로 사용하려면 어떻게해야합니까?

도움이 되었습니까?

해결책

사용 HttpWebRequest.BeginGetResponse()

HttpWebRequest webRequest;

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

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

비동기 작동이 완료되면 콜백 함수가 호출됩니다. 적어도 전화해야합니다 EndGetResponse() 이 기능에서.

다른 팁

답을 고려 :

HttpWebRequest webRequest;

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

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

요청 포인터 또는 이와 같은 다른 객체를 보낼 수 있습니다.

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

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

인사말

지금까지 모든 사람이 잘못되었습니다. 왜냐하면 BeginGetResponse() 일부는 현재 스레드에서 작동합니다. 로부터 선적 서류 비치:

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);
}

그런 다음 응답으로 필요한 작업을 수행 할 수 있습니다. 예를 들어:

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

가장 쉬운 방법은 사용하는 것입니다 TaskFactory.fromasync ~로부터 tpl. 말 그대로 새로운 코드 라인입니다. 비동기/기다립니다 키워드 :

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);

C#5 컴파일러를 사용할 수없는 경우 위의 내용은 다음을 사용하여 달성 할 수 있습니다. task.continuewith 방법:

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

나는 백그라운드 worker를 사용하게되었고, 위의 솔루션 중 일부와 달리 비동기식이며, GUI 스레드로 돌아 오는 것을 처리하며 이해하기가 매우 쉽습니다.

런 워크 커플 셋 방법으로 끝나기 때문에 예외를 처리하기가 매우 쉽지만 다음을 읽으십시오. 백그라운드 워크 인의 대립되지 않은 예외

나는 WebClient를 사용했지만 분명히 원하는 경우 httpwebrequest.getResponse를 사용할 수 있습니다.

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();

이러한 답변 중 많은 부분이 게시 된 이후 .NET이 변경되었으며보다 최신 답변을 제공하고 싶습니다. 비동기 방법을 사용하여 시작하십시오 Task 배경 스레드에서 실행됩니다.

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;
}

비동기 방법을 사용하려면 :

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

업데이트:

이 솔루션은 사용하는 UWP 앱에서는 작동하지 않습니다. WebRequest.GetResponseAsync() 대신에 WebRequest.GetResponse(), 그리고 그것은 전화를하지 않습니다 Dispose() 적절한 경우 방법. @dragansr에는 이러한 문제를 해결하는 좋은 대안 솔루션이 있습니다.

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);
        } 
    }
public static async Task<byte[]> GetBytesAsync(string url) {
    var request = (HttpWebRequest)WebRequest.Create(url);
    using (var response = await request.GetResponseAsync())
    using (var content = new MemoryStream())
    using (var responseStream = response.GetResponseStream()) {
        await responseStream.CopyToAsync(content);
        return content.ToArray();
    }
}

public static async Task<string> GetStringAsync(string url) {
    var bytes = await GetBytesAsync(url);
    return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top