Appel des interfaces invocables

De RAD Studio
Aller à : navigation, rechercher

Remonter à Conception de clients pour les services Web


Pour appeler une interface invocable, l'application client doit inclure toutes les définitions des interfaces invocables et toutes les classes distantes implémentant des types complexes.

Si le serveur est conçu avec Delphi ou C++Builder, vous pouvez recourir aux mêmes unités que celles utilisées par l'application serveur pour définir et recenser ces interfaces et ces classes à la place des fichiers issus de l'importation d'un fichier WSDL. Assurez-vous que l'unité utilise les mêmes URI d'espace de nommage et en-tête SOAPAction lorsqu'elle recense des interfaces invocables. Ces valeurs peuvent être spécifiées explicitement dans le code qui recense les interfaces ou être générées automatiquement. Si elle est générée automatiquement, l'unité qui définit les interfaces doit porter le même nom dans le client et le serveur ; le client et le serveur doivent tous deux définir la variable globale AppNameSpacePrefix d'après la même valeur.

Lorsque vous disposez de la définition de l'interface invocable, il existe deux façons pour obtenir une instance d'appel :

  • Si vous avez importé un document WSDL, l'importateur génère automatiquement une fonction globale qui renvoie l'interface, que vous pouvez ensuite appeler.
  • Vous pouvez utiliser un objet interfacé distant.

Obtention d'une interface invocable à partir de la fonction générée

L'importateur WSDL génère automatiquement une fonction à partir de laquelle vous pouvez obtenir les interfaces invocables importées. Par exemple, si vous avez importé un document WSDL définissant une interface invocable nommée IServerInterface, l'unité générée devrait inclure la fonction globale suivante :

function GetIServerInterface(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): IServerInterface;
 
_di_IServerInterface GetIServerInterface(bool UseWSDL, AnsiString Addr, THTTPRIO* HTTPRIO);

La fonction générée accepte trois paramètres : UseWSDL, Addr, et HTTPRio. UseWSDL indique si la recherche de l'emplacement du serveur s'effectue à partir d'un document WSDL (true), ou si l'application client fournit l'URL du serveur (false).

Quand UseWSDL a pour valeur false, Addr est l'URL du service Web. Quand UseWSDL a pour valeur true, Addr est l'URL d'un document WSDL qui décrit le service Web que vous appelez. Si vous fournissez une chaîne vide, le document importé représente la valeur par défaut. Cette seconde approche est meilleure si vous prévoyez une modification de l'URL du service Web, de l'espace de nommage ou de l'en-tête Action SOAP. Avec cette seconde approche, cette information est recherchée dynamiquement au moment où votre application effectue l'appel de méthode.

Remarque : Pour des raisons de performances, il est préférable d'utiliser une URL à la place d'un paramètre WSDL. Pour WSDL, le runtime SOAP doit exécuter un HTTP GET pour le paramètre WSDL avant d'invoquer une opération de service Web. Le paramètre HTTPRio spécifie l'objet d'interface distant à utiliser pour obtenir l'interface. Si vous spécifiez une valeur NULL pour le paramètre HTTPRio la méthode crée une nouvelle instance THTTPRio. Vous pouvez spécifier l'instance THTTPRio si vous souhaitez utiliser l'inspecteur d'objets afin de personnaliser l'objet et gérer les événements.

Remarque : La fonction générée utilise un objet interfacé distant interne pour implémenter l'interface invocable. Si vous utilisez cette fonction et devez accéder à cet objet interfacé distant sous-jacent, vous pouvez obtenir une interface IRIOAccess à partir de l'interface invocable puis l'utiliser pour accéder à l'objet interfacé :

 var
   Interf: IServerInterface;
   RIOAccess: IRIOAccess;
   X: THTTPRIO;
 begin
   Intrf := GetIServerInterface(True,
           'http://MyServices.org/scripts/AppServer.dll/wsdl');
   RIOAccess := Intrf as IRIOAccess;
   X := RIOAccess.RIO as THTTPRIO;
 
 _di_EchoUnboundedSoap service = GetEchoUnboundedSoap();
   _di_IRIOAccess rioAccess = service;
   TSOAPConvertOptions options = rioAccess->GetRIO()->Converter->GetOptions();

Utilisation d'un objet interfacé distant

Si vous n'utilisez pas la fonction globale pour obtenir l'interface invocable à appeler, vous pouvez créer une instance de Soap.SOAPHTTPClient.THTTPRIO pour l'interface désirée :

 X := THTTPRio.Create(nil);
 
 X = new THTTPRio(NULL);

Remarque : Il est important de ne pas détruire explicitement l'instance de THTTPRio. Si elle est créée sans un Owner (comme dans la ligne de code précédente), elle se libère automatiquement lorsque son interface est libérée. Si elle est créée avec un Owner, le Owner est responsable de la libération de l'instance de THTTPRio.

Une fois que vous disposez d'une instance de HTTPRio, fournissez-lui les informations lui permettant d'identifier l'interface du serveur et de localiser le serveur. Il y a deux manières de spécifier ces informations :

Si l'URL du service Web ou les espaces de nommage et en-têtes d'action SOAP dont elle a besoin ne sont pas censés changer, vous pouvez spécifier simplement l'URL du service Web auquel vous voulez accéder. THTTPRio utilise cette URL pour rechercher la définition de l'interface, plus l'espace de nommage et les informations d'en-tête, en se basant sur les informations du registre d'invocation. Spécifiez l'URL en initialisant la propriété URL à l'emplacement du serveur.

 X.URL := 'http://www.myco.com/MyService.dll/SOAP/IServerInterface';

Si vous voulez rechercher l'URL, l'espace de nommage ou l'en-tête d'action Soap à partir du document WSDL, dynamiquement lors de l'exécution, vous pouvez utiliser les propriétés SDLLocation, Service, et Port. Les informations nécessaires seront alors extraites du document WSDL :

 X.WSDLLocation := 'Cryptography.wsdl';
 X.Service := 'Cryptography';
 X.Port := 'SoapEncodeDecode';

Après avoir spécifié comment localiser le serveur et identifier l'interface, vous pouvez obtenir un pointeur d'interface pour l'interface invocable à partir de l'objet THTTPRio. Vous obtenez ce pointeur d'interface à l'aide de l'opérateur as. Il suffit de transtyper l'instance THTTPRio vers l'interface invocable :

 InterfaceVariable := X as IEncodeDecode;
 Code := InterfaceVariable.EncodeValue(5);
 
 _di_IEncodeDecode InterfaceVariable;
 if (X->QueryInterface(InterfaceVariable) == S_OK)
 {
   Code = InterfaceVariable->EncodeValue(5);
 }

Lorsque vous obtenez le pointeur d'interface, THTTPRio crée dynamiquement en mémoire une vtable pour l'interface associée, ce qui permet d'effectuer les appels de l'interface.

THTTPRio se base sur le registre d'invocation pour obtenir des informations sur l'interface invocable. Si l'application client n'a pas de registre d'invocation ou si l'interface invocable n'est pas recensée, THTTPRio ne peut pas construire sa vtable en mémoire.

Avertissement : Si vous affectez l'interface obtenue auprès de THTTPRio à une variable globale, vous devrez lui réaffecter nil avant d'arrêter votre application. Par exemple, si InterfaceVariable dans l'exemple de code précédent est une variable globale et non une variable de la pile, vous devrez libérer l'interface avant de libérer l'objet THTTPRio. Généralement, ce code apparaît dans le gestionnaire d'événement OnDestroy de la fiche ou du module de données :

 procedure TForm1.FormDestroy(Sender: TObject);
 begin
   InterfaceVariable := nil;
 end;
 void __fastcall TForm1::FormDestroy(TObject *Sender)
 {
   InterfaceVariable = NULL;
 }

La raison pour laquelle vous devez réaffecter à une variable d'interface globale la valeur nil tient au fait que THTTPRio construit dynamiquement sa vtable en mémoire. Cette vtable doit toujours être présente quand l'interface est libérée. Si vous ne libérez pas l'interface avec la fiche ou le module de données, elle est libérée lorsque la variable globale est libérée à la fermeture. La mémoire des variables globales peut être libérée après la fiche ou le module de données contenant l'objet THTTPRio, auquel cas la vtable ne sera pas disponible lorsque l'interface sera libérée.

Voir aussi