IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Récupérer un flux web de manière asynchrone en C#

Ce tutoriel vise à expliquer comment en C# effectuer des requêtes HTTP afin de récupérer un contenu web de façon asynchrone. ♪

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

Avant-Propos

En C#, il existe plusieurs manières d'interroger une ressource web afin de récupérer sa source (HTML, XML…). La manière la plus simple et la plus fréquemment utilisée consiste à faire appel à la méthode WebRequest.GetResponse. Néanmoins cette dernière possède un inconvénient majeur dans la mesure où cette opération est synchrone et génère un temps de latence assez important, et ce, même pour récupérer un flux web de petite taille.

I. Utilisation de la méthode BeginGetResponse

La méthode BeginGetResponse permet d'interroger un flux de manière asynchrone pour ce faire, il suffit de lui indiquer en tant que premier argument l'adresse d'une méthode callback. Le deuxième argument à spécifier est un objet appelle couramment state (état). Cet objet état permet d'établir une connexion logique entre le thread principal effectuant requête initiale et la méthode de callback appelée à s'exécuter au sein d'un thread différent.

Il est nécessaire par ailleurs de définir et d'instancier sa propre classe d'état à passer en argument. Cette classe peut contenir des références aux objets que vous souhaitez transmettre a votre callback notamment une référence sur l'objet HttpWebRequest comme illustre dans le code ci-dessous :

Utilisation de BeginGetResponse
Sélectionnez
// La classe RequestState est utilisée pour transmettre l'objet HttpWebRequest 
// à travers l'appel asynchrone
public class RequestState
{
    public HttpWebRequest Request;

    public RequestState()
    {
        Request = null;
    }
}

/// Classe effectuant un appel HTTP GET asynchrone ver une URL
public class GetHttpAsync
{
    public void getPage(string url)
    {
    HttpWebRequest req = (HttpWebRequest) WebRequest.Create(url);
        // Création de l'objet état
        RequestState rs = new RequestState();
        //On ajoute la requête dans l'objet état pour pouvoir le récupérer dans la callback
        rs.Request = req;

        / / Appel asynchrone
        req.BeginGetResponse(new AsyncCallback(this.ResponseCallback), rs);
    }
}

Par la suite, dans la callback, il suffit de faire appel à la propriété AsyncRequest pour récupérer l'objet RequestState (état), et ainsi l'objet HttpWebRequest. Enfin, l'appel a la méthode EndGetResponse permet de récupérer l'objet HttpWebResponse. Il est ensuite possible de procéder comme si vous aviez fait un appel synchrone.

Utilisation de ResponseCallback
Sélectionnez
private void ResponseCallback(IAsyncResult ar)
{
    //Récupération de l'objet etat 
    RequestState rs = (RequestState) ar.AsyncState;
    //Récupération de la requête web (object HttpWebRequest)
    HttpWebRequest req = rs.Request;
    //Récupération de la réponse web    
    HttpWebResponse resp = (HttpWebResponse) req.EndGetResponse(ar);

    Stream responseStream = resp.GetResponseStream();
    StreamReader sr = new StreamReader(responseStream, Encoding.UTF8);
    string strContent = sr.ReadToEnd();

    responseStream.Close();
}

II. Gestion d'un timeout

Pour terminer, je souhaitais répondre à une question qui revient souvent dans les forums dotnet que j'ai eu l'occasion de fréquenter à savoir comment annuler une requête HTTP s'exécutant de manière asynchrone. Ce qui peut être vivement souhaité si l'opération prend trop de temps (si le serveur web que l'on souhaite interroger est surchargé par exemple).

Il est possible d'annuler une requête en appelant la méthode Abort sur l'objet HttpWebRequest. Il existe plusieurs manières d'enregistrer un timeout sur une requête HTTP et d'annuler cette dernière une fois que le timeout est dépassé. La méthode la plus simple consiste à utiliser le thread pool du framework .NET en utilisant la méthode WaitOrTimerCallback et d'y associer une méthode déléguée comme le montre le code ci-dessous :

Utilisation d'un timeout
Sélectionnez
/// Classe effectuant un appel HTTP GET asynchrone avec timeout
public void DoAsyncWithTimeout(string url)
{
    RequestState rs = new RequestState();
    rs.Request = (HttpWebRequest) WebRequest.Create(url);
    
    // Appel asynchrone
    IAsyncResult ar = rs.Request.BeginGetResponse(new AsyncCallback(this.ResponseCallback) , rs);
    
    // Définition du timeout
    ThreadPool.RegisterWaitForSingleObject( ar.AsyncWaitHandle, 
                                            new WaitOrTimerCallback(RequestTimeoutCallback), 
                                            rs, 10 * 1000,  // timeout de 10 secondes
                                            true
                                            );
}

static void RequestTimeoutCallback(object state, bool timedout)
{
    if (timedout == true)
    {
        RequestState rs = (RequestState) state;
        if ((rs != null) && (rs.Request != null))
        {
            rs.Request.Abort();
        }
    }
}

Dans le code précédant, si la callback enregistrée lors de l'appel BeginGetResponse ne s'exécute pas dans les 10 secondes, la méthode déléguée RequestTimeoutCallback sera invoquée. Notez bien que l'objet état associé à la requête asynchrone est aussi passé en tant qu'argument au délégué. En effet, dans cette méthode, nous avons besoin de l'objet HttpWebRequest pour annuler la requête http en appelant la méthode Abort.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Copyright © 2005 Pierre Jallais. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.