Produits  
  Services et Conseils  
  Fiches Technique  
  SipXTapi avec .Net  
  transformNode en .Net  
  Blowfish et le CF  
  MD5 et le CF  
  Compression HTTP et le CF  
 
 

  Fiches Technique  


Comment appeler des Services Web avec le Compact Framework
sur PocketPC en utilisant la Compression HTTP/1.1

read the English version

Principe général
Implémenter ZHttpWebRequest
Implémenter ZHttpWebResponse
Enregistrer le protocole
Changer l'Url du WebService
Configurer IIS 5.0 pour compresser les fichiers aspx et asmx
Quelques liens utiles...
Historique de révisions...

Dans son tutorial Retrieving Data from Web Services using Standard HTTP 1.1 Compression, Jacek Chmiel explique comment, en .NET, surcharger les méthodes GetWebRequest et GetWebResponse de la classe proxy du Web Service pour demander au serveur la compression des données et les décompresser avant l'interprétation de l'enveloppe SOAP.

Cette approche, très intéressante, ne s'applique malheureusement pas au PocketPC car le Compact Framework ne permet pas la surcharge de ces méthodes. En revanche, nous nous sommes rendus compte qu'il est possible de définir un nouveau protocole, zhttp par exemple, qui utilise des objets WebRequest et WebResponse adaptés pour la compression.

Et cette approche marche sur PocketPC !

Cet article a été rédigé avec la version Beta du Compact Framework.

  • Pour obtenir les binaires de la version de zhttp compatible avec la Final Beta, cliquez ici.
  • Pour obtenir les fichiers sources qui utilisent le dernière version de SharpZipLib, au lieu de l'ancienne version NZipLib, cliquez ici.
    Dans cette version, l'implémentation de ZHttpWebRequest surcharge la propriété WebRequest.Timeout en déléguant son appel à l'objet HttpWebRequest sous-jacent. Ne pas le faire entraine l'envoi d'une NotSupportedException en cas d'utilisation de la propriété Timeout.

Principe général

A priori, la phase de transport HTTP d'un appel SOAP est la suivante :

  • création d'une requête HTTP via Webrequest.Create sur le protocole http ;
  • préparation de la requête pour envoyer l'enveloppe SOAP ;
  • demande de la réponse ;
  • lecture du flux de la réponse pour interpréter l'enveloppe SOAP de résultat.

Sans rien changer au fonctionnement des WebServices et des objets SOAP coté client et coté serveur, le code que nous allons mettre en place nous permettra d'obtenir la phase de transport suivante :

  • enregistrement du protocole zhttp ;
  • création d'une requête HTTP via WebRequest.Create sur le protocole zhttp ;
  • création de la requête HTTP sous-jacente via WebRequest.Create, sans le "z" ;
  • ajout de l'en-tête "Accept-Encoding: gzip, deflate";
  • préparation de la requête pour envoyer l'enveloppe SOAP ;
  • demande de la réponse ;
  • demande de la réponse de la requête sous-jacente ;
  • décompression du flux de la réponse sous-jacente ;
  • lecture du flux de la réponse pour interpréter l'enveloppe SOAP de résulat.

Implémenter ZHttpWebRequest

Nous commençons par implémeter la classe qui permet de créer une requête HTTP en précisant dans les en-têtes que le client sait traiter les réponses compressées, soit en gzip, soit en deflate. Si le serveur ne connaît aucune des deux méthodes, il renvoie les données non-compressées.

public class ZHttpWebRequest : System.Net.WebRequest
{
    private HttpWebRequest request;
    private System.Uri uri;

    internal ZHttpWebRequest(System.Uri uri)
    {
        string s = uri.AbsoluteUri.Substring(1); // remove the leading z
        this.uri = uri;
        request = (HttpWebRequest)WebRequest.Create(s);
        
        // tell the HTTP server that the client accept compressed data
        request.Headers.Add("Accept-Encoding", "gzip, deflate");
    }

Ensuite, il suffit que la méthode GetResponse renvoie notre objet qui se charge de décompresser les informations renvoyées par le serveur HTTP.

    public override System.Net.WebResponse GetResponse()
    {
        ZHttpWebResponse response = null;
        
        // create the appropriate response object
        response = new ZHttpWebResponse(request, uri);
        return response;
    }

Enfin, pour toutes les autres méthodes pouvant être surchargées, nous appelons directement l'objet de requête HTTP sous-jacent.

    // for all the other overridable functions, redirect the call 
    // to the private HttpRequest object, as shown above
    public override void Abort()
    {
        request.Abort(); // redirect the call 
    }
    ...
}

Implémenter ZHttpWebResponse

Pour traiter la réponse, nous devons développer un nouvel objet qui dérive de WebResponse et qui encapsule l'objet réponse HTTP classique.

public class ZHttpWebResponse : WebResponse
{
    private HttpWebResponse response;
    private System.Uri uri;

    internal ZHttpWebResponse(WebRequest request, System.Uri uri)
    {
        this.uri = uri;
        response = (HttpWebResponse)request.GetResponse();
    }

C'est dans la méthode GetResponseStream que nous devons faire le travail de décompression, en tenant compte de la réponse du serveur : soit la réponse est encodée en "gzip", soit en "deflate" ou sinon elle n'est encodée pas du tout.

    public override Stream GetResponseStream()
    {
        // select the right decompression stream
        if(response.ContentEncoding=="gzip")
        {
            return new GZipInputStream(response.GetResponseStream());
        }
        else if(response.ContentEncoding=="deflate")
        {
            return new InflaterInputStream(response.GetResponseStream());
        }
        else
        {
            return response.GetResponseStream();
        }
    }

Puis, nous surchargeons la méthode ResponseUri pour utiliser l'Uri initiale. Et finalement, pour toutes les autres méthodes pouvant être surchargées, nous appelons directement l'objet de réponse HTTP sous-jacent.

    public override System.Uri ResponseUri
    {
        get
        {
            return uri;
        }
    }

    // for all the other overridable functions, redirect the call 
    // to the private HttpRequest object, as shown above
    public override void Close()
    {
        response.Close();
    }
    ...
}

Enregistrer le protocole

Les requêtes Web sont gérés via une fabrique de classes qui instancie les objets WebRequest en fonction du préfixe de l'uri. Ainsi, http:// est traité par HttpWebRequest, file:// par FileWebRequest, etc.

Pour enregistrer notre protocole, nous devons d'abord créer une classe implémentant l'interface IWebRequestCreate, qui permettra à la fabrique d' instancier nos objets ZHttpWebRequest.

class ZHttpWebRequestCreate : IWebRequestCreate
{
    /// <summary>
    /// Create the WebRequest object able to handle the Uri
    /// </summary>
    /// <param name="uri">the requested Uri</param>
    /// <returns>The WebRequest object</returns>
    public System.Net.WebRequest Create(System.Uri uri)
    {
        System.Net.WebRequest request = new ZHttpWebRequest(uri);
        return request;
    }
}

Ensuite, pour être plus propre, nous encapsulons dans une méthode l'appel à l'enregistrement du préfixe et l'objet de création dans la fabrique.

public class ZHttpProtocol
{
    /// <summary>
    /// Register the protocol
    /// </summary>
    /// <returns></returns>
    static public bool Register()
    {
        return WebRequest.RegisterPrefix("zhttp", 
                                         new ZHttpWebRequestCreate());
    }
}

Il ne nous reste plus qu'a appeler la méthode ZHttpProtocol.Register dans notre programme, avant d'appeler les WebServices, dans la méthode Main par exemple.

// register the protocol
ZHttpProtocol.Register();

Changer l'Url du WebService

Lors du référencement des WebService via le Web, les Uri des fichiers WSDL sont en http://. Donc, pour utiliser notre protocole, il nous suffit d'ajouter le z devant l'Uri normal.

// initiliaze the WebService
MyWebService ws = new MyWebService();
ws.Url = "z" + ws.Url;

// call the methods
...

Et voilà !

Configurer IIS 5.0 pour compresser les fichiers aspx et asmx

Pour compresser les fichiers aspx et asmx sur un serveur IIS, nous devons activer la compression HTTP sur le serveur puis exécuter les commandes suivantes :

CSCRIPT.EXE ADSUTIL.VBS 
  SET W3Svc/Filters/Compression/GZIP/HcScriptFileExtensions 
  "dll" "asp" "aspx" "asmx"¶
¶
CSCRIPT.EXE ADSUTIL.VBS¶
  SET W3Svc/Filters/Compression/DEFLATE/HcScriptFileExtensions 
  "dll" "asp" "aspx" "asmx"¶
¶
IISRESET.EXE¶

Quelques liens utiles...

Retrieving Data from Web Services using Standard HTTP 1.1 Compression
article de Jacek Chmiel sur www.dotnetjunkies.com
Librairie de compression/décompression SharpZipLib
site où télécharger la SharpZipLib
Programming Pluggable Protocols
article du msdn expliquant comment implémenter des "Pluggable Protocols"
Télécharger le source
taille : 2 Ko, dernière modification : 26/01/2004
Téléchargez les binaires de la version compatible avec la Final Beta
Cet assembly inclut un sous ensemble des classes de NZipLib, un version antérieure de SharpZipLib.
taille : 21 Ko, dernière modification : 29/11/2002
Nous contacter
Vous avez des remarques, des questions ? N'hésitez pas à nous contacter.

Historique de révisions...

date révision
26/01/2004 Mise à jour du fichier source
Ajout à la ligne 374 de l'implémentation de la propriété Headers pour éviter une exception NotSupportedException. (Merci à Jeff Evans pour avoir remonté et corrigé le bug).

les informations fournies ici le sont en tant que telles, sans aucune garantie d'aucune sorte.
Copyright © FlowGroup SAS, 2002-2005