Как я могу использовать HttpWebRequest (.NET, С#) асинхронно?
Как использовать HttpWebRequest (.NET) асинхронно?
Ответ 1
Используйте HttpWebRequest.BeginGetResponse()
HttpWebRequest webRequest;
void StartWebRequest()
{
webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), null);
}
void FinishWebRequest(IAsyncResult result)
{
webRequest.EndGetResponse(result);
}
Функция обратного вызова вызывается, когда асинхронная операция завершена. Вам нужно как минимум вызвать EndGetResponse()
из этой функции.
Ответ 2
Учитывая ответ:
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;
}
Привет
Ответ 3
Все до сих пор ошибались, потому что 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);
});
Ответ 4
Самым простым способом является TaskFactory.FromAsync из TPL. Это буквально пара строк кода при использовании в сочетании с новым async/wait ниже:
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);
Если вы не можете использовать компилятор С# 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);
});
Ответ 5
Я закончил использование BackgroundWorker, он определенно асинхронен, в отличие от некоторых из вышеперечисленных решений, он обращается к потоку GUI для вас, и это очень легко понять.
Также очень легко обрабатывать исключения, поскольку они попадают в метод RunWorkerCompleted, но убедитесь, что вы читаете это: Необработанные исключения в BackgroundWorker
Я использовал 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();
Ответ 6
public void GetResponseAsync (HttpWebRequest request, Action<HttpWebResponse> gotResponse)
{
if (request != null) {
request.BeginGetRequestStream ((r) => {
try { // there 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);
}
}
Ответ 7
.NET изменился, так как многие из этих ответов были опубликованы, и я хотел бы предоставить более современный ответ. Используйте метод async для запуска 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;
}
Чтобы использовать метод async:
String response = await MakeRequestAsync("http://example.com/");