Comment appeler des Services Web avec le Compact Framework
sur PocketPC en utilisant la Compression HTTP/1.1
read the English version
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...
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