HttpWebRequest (.NET)를 비동기 적으로 사용하는 방법은 무엇입니까?
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);
});
가장 쉬운 방법은 TPL 에서 TaskFactory.FromAsync 를 사용하는 것 입니다. 새로운 async / await 키워드 와 함께 사용하면 말 그대로 몇 줄의 코드입니다 .
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);
If you can't use the C#5 compiler then the above can be accomplished using the Task.ContinueWith method:
Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse,
request.EndGetResponse,
null)
.ContinueWith(task =>
{
var response = (HttpWebResponse) task.Result;
Debug.Assert(response.StatusCode == HttpStatusCode.OK);
});
I ended up using BackgroundWorker, it is definitely asynchronous unlike some of the above solutions, it handles returning to the GUI thread for you, and it is very easy to understand.
It is also very easy to handle exceptions, as they end up in the RunWorkerCompleted method, but make sure you read this: Unhandled exceptions in BackgroundWorker
I used WebClient but obviously you could use HttpWebRequest.GetResponse if you wanted.
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 has changed since many of these answers were posted, and I'd like to provide a more up-to-date answer. Use an async method to start a Task
that will run on a background thread:
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;
}
To use the async method:
String response = await MakeRequestAsync("http://example.com/");
Update:
This solution does not work for UWP apps which use WebRequest.GetResponseAsync()
instead of WebRequest.GetResponse()
, and it does not call the Dispose()
methods where appropriate. @dragansr has a good alternative solution that addresses these issues.
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);
}
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);
}
}
참고URL : https://stackoverflow.com/questions/202481/how-to-use-httpwebrequest-net-asynchronously
'IT story' 카테고리의 다른 글
process.env.NODE_ENV가 정의되지 않았습니다 (0) | 2020.06.12 |
---|---|
github에서 gem의 특정“커밋”을 얻는 방법은 무엇입니까? (0) | 2020.06.12 |
“잘못된 문자열 값”오류를 수정하는 방법? (0) | 2020.06.12 |
Macports를 업데이트 할 수 없습니다 (Mac OS X Mavericks 사용) (0) | 2020.06.12 |
자식을 정리하는 방법이 있습니까? (0) | 2020.06.12 |