Domanda

Come posso usare HttpWebRequest (.NET, C #) in modo asincrono?

È stato utile?

Soluzione

Usa HttpWebRequest.BeginGetResponse ()

HttpWebRequest webRequest;

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

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

La funzione di richiamata viene chiamata al termine dell'operazione asincrona. Devi almeno chiamare EndGetResponse () da questa funzione.

Altri suggerimenti

Considerando la risposta:

HttpWebRequest webRequest;

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

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

È possibile inviare il puntatore della richiesta o qualsiasi altro oggetto come questo:

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

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

Un saluto

Finora tutti hanno sbagliato, perché BeginGetResponse () funziona un po 'sul thread corrente. Dalla documentazione :

  

Il metodo BeginGetResponse richiede alcune attività di configurazione sincrona per   completo (risoluzione DNS, rilevamento proxy e connessione socket TCP,   per esempio) prima che questo metodo diventi asincrono. Di conseguenza,   questo metodo non deve mai essere chiamato su un thread dell'interfaccia utente (UI)   perché potrebbe richiedere molto tempo (fino a diversi minuti   a seconda delle impostazioni di rete) per completare la sincronizzazione iniziale   attività di installazione prima che venga generata un'eccezione per un errore o il metodo   riesce.

Quindi, per fare questo nel modo giusto:

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

Puoi quindi fare ciò di cui hai bisogno con la risposta. Ad esempio:

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

Di gran lunga il modo più semplice è utilizzare TaskFactory.FromAsync dal TPL . È letteralmente un paio di righe di codice quando utilizzato insieme al nuovo async / waitit parole chiave:

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

Se non è possibile utilizzare il compilatore C # 5, è possibile eseguire quanto sopra utilizzando Metodo Task.ContinueWith :

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

Ho finito con BackgroundWorker, è decisamente asincrono a differenza di alcune delle soluzioni precedenti, gestisce il ritorno al thread della GUI per te ed è molto facile da capire.

È anche molto facile gestire le eccezioni, poiché finiscono nel metodo RunWorkerCompleted, ma assicurati di leggere questo: Eccezioni non gestite in BackgroundWorker

Ho usato WebClient ma ovviamente potresti usare HttpWebRequest.GetResponse se lo desideri.

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 è cambiato da quando sono state pubblicate molte di queste risposte e vorrei fornire una risposta più aggiornata. Utilizzare un metodo asincrono per avviare un Task che verrà eseguito su un thread in background:

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

Per utilizzare il metodo asincrono:

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

Aggiornamento:

Questa soluzione non funziona con le app UWP che utilizzano WebRequest.GetResponseAsync () invece di WebRequest.GetResponse () e non chiama Dispose () ove appropriato. @dragansr ha una buona soluzione alternativa che risolve questi problemi.

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);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top