Services Web
Service
Définition
Un service Web est un composant applicatif accessible sur le Web par une interface standard en utilisant des protocoles de communication basés sur le XML indépendamment du système d'exploitation et des langages de programmation utilisés.
Le service Web met à disposition des fonctions (méthodes) sur un serveur HTTP.
Le client du service Web peut invoquer la méthode du serveur aussi simplement que s'il s'agissait d'une fonction locale. Il faut spécifier l'URL du service Web auquel on désire accéder, ainsi que les paramètres d'entrée de la méthode.
WebServiceDIva
WebServiceDiva est une méthode générique permettant d'exécuter une action sur le serveur Web. L'action correspond à un programme Diva. Celui-ci récupère les paramètres (généralement une chaîne <hmp>), effectue le traitement et renvoie un résultat.
Le service est exécuté par le serveur HTTP IIS de Microsoft.
Architecture
WebServiceDiva
WebServiceDiva est un service Web générique qui sert à lancer tous les services Web Diva. La page générique WebserviceDiva.asmx est hébergée sur le serveur IIS de Microsoft. Elle contient la méthode WebServiceDiva qui permet d'exécuter un programme Diva sur le serveur en lui passant des paramètres
Int WebServiceDiva(string action,string param,out string retour)
Action : une chaîne au format <HMP>,
Param : généralement une chaîne au format <HMP>
Retour : généralement une chaîne au format <HMP>
Il peut être appelé depuis un programme Diva et depuis n'importe quelle autre application cliente de services Web.
Il exécute le programme XWebServices.dhop
Remarque :
Pour l'appel d'un service Web Diva depuis un programme Diva il faut utiliser la fonction WebServiceDivaExecute.
XwebServices
Le programme XwebServices.dhop est exécuté à chaque invocation d'un service Web Diva. C'est lui qui lance le programme Diva correspondant à l'action demandée.
Le programme de traitement de l'action est lancé par la fonction ProgramGoto. XwebServices.dhop lui envoie les paramètres par le tunnel.
Actions des services Web
Le paramètre <Action> permet de préciser l'action à exécuter pour ce message. Ce paramètre est obligatoirement une chaîne HMP dans laquelle le paramètre <ACTION> définit le traitement à effectuer. Il fait référence à une action décrite dans le fichier paramètres des actions. Ce fichier contient pour chaque action :
Un commentaire décrivant l'action.
Un indicateur de validité de l'action. Celui-ci permet de d'interdire provisoirement l'exécution d'une action.
Un indicateur permettant de garder le programme XwebServices en résident. (voir Services Web résidents)
Le nom du programme Diva qui traite l'action.
Le code utilisateur sous lequel le programme Diva doit s'exécuter.
Des paramètres complémentaires de l'action sous forme de chaîne de commandes HMP.
Algorithme général de XwebServices.dhop
Lorsque XwebServices.dhop est invoqué, il effectue les opérations suivantes.
Recherche de l'action dans le fichier des actions. Si l'action est absente ou bien n'est pas active, il renvoie un code d'erreur avec un message dans le paramètre de retour.
Chargement des droits et des chemins implicites de l'utilisateur lié à l'action. S'il n'est pas renseigné, le programme s'exécute avec le code utilisateur $WEBSERVICE.
Envoi des paramètres du service Web, ainsi que des paramètres complémentaires en provenance du fichier des actions au programme Diva par le tunnel.
Exécution du traitement
par l'instruction "ProgramGoto" si l'action est paramétrée comme résidente.
par la fonction "ProgramCall" avec attente de la fin du traitement si l'action n'est pas paramétrée comme résidente..
Si le traitement est appelé par ProgramCall
Attente de l'acquittement du traitement par la fonction "PongReceive" de "WebServiceStatus". En cas d'absence d'acquittement renvoi d'un code d'erreur.
Réception de la réponse et éventuellement d'un numéro de version du service Diva
Journalisation de l'exécution de l'action dans le fichier XwebServices.log avec la date, l'heure ainsi que la durée d'exécution de l'action.
Si le traitement est appelé par ProgramGoto
c'est à ce dernier de renvoyer la réponse en utilisant la fonction WebServiceReturn.
Remarques :
L'action « ping » permet de tester les services Web sans avoir à écrire de programme Diva. Elle est directement traitée par le programme XwebServices.dhop. Pour cela elle doit être créée et activée dans le fichier paramètre des actions. XwebServices renvoie un status à 0 et dans le paramètre de retour sa version ainsi que le nom du serveur sur lequel il s'exécute.
La durée de l'exécution de l'action doit être relativement courte. Le client attend la réponse en temps réel. Si le traitement est trop long, la liaison avec le client risque d'être interrompue.
Le service Web Diva est un programme qui n'effectue pas d'affichage.
Si le paramètre Résidente de l'action n'est pas cochée, l'appel du programme se fait par un ProgramCall ce qui est nettement plus coûteux en temps.
Voir également :
Rubrique "Harmony Markup Parameters HMP" de la documentation Xwin - Programmation.
Rubrique "Tunnels" de la documentation Xwin - Programmation.
Rubrique "ProgramCall" de la documentation Xwin - Programmation.
Service Web Diva
Le service Web Diva est le programme chargé d'exécuter l'action demandée par le client du service Web.
Il récupère dans le tunnel par la fonction PingReceive les paramètres suivants :
WebServiceAction | La chaîne <action>. En plus du paramètre Action, cette chaîne peut comporter des paramètres complémentaires. Elle n'est jamais cryptée. |
WebServiceParameters | Les paramètres d'entrée de l'action. S'il y a plusieurs paramètres, on utilisera de préférence une chaîne au format <hmp>. Pour des besoins de confidentialité, ce paramètre peut être crypté. |
WebServiceParametersUnicode | Chaîne Unicode fournie par Dotnet. |
WebServiceParamAction | Les paramètres complémentaires en provenance du fichier des actions. |
Si l'action est paramétrée résidente
Il traite l'action et renvoie le résultat par la fonction WebServiceReturn.
Il enchaîne au programme XwebServices.dhop par l'instruction ProgramGoto
Si l'action n'est pas paramétrée résidente :
Il traite l'action puis renvoie les résultats dans le tunnel par la fonction Pong
WebServiceStatus | Le compte-rendu. La valeur 0 indique un traitement sans erreur. Une valeur différente de 0 correspond à une erreur de traitement. Dans ce cas, il est préférable de mettre un message d'erreur en clair dans le résultat. |
WebServiceResult | Le résultat ou un message d'erreur. Le résultat peut être crypté lorsque WebServiceStatus est nul. |
WebServiceVersion | (facultatif) Le numéro de version est journalisé dans le fichier XwebServices.log. |
Puis il se termine par l'instruction ProgramExit.
Remarques :
Pour stocker les paramètres de type <hmp>, on utilisera de préférence une donnée de type 'S' dont la taille s'adapte automatiquement au contenu.
La fonction ServiceMode renvoie la valeur 3 si le programme est invoqué par un service Web.
Services Web résidents
Principe
A partir de la version 6.3a d'Harmony, le système gère un pool de tâches pour l'exécution des services web. Ce pool permet de garder des tâches Harmony en attente et ainsi de réduire considérablement le temps d'exécution d'une requête.
Lors du premier appel à un service web, le programme XwebServices.dhop est chargé. Une fois le traitement de l'action effectué, le contrôle est rendu au programme XwebServices.dhop (par l'instruction ProgramGoto). Ce dernier se met alors en attente d'un appel de service web.
Lors de l'appel suivant à un service web, s'il existe une tâche disponible dans le pool, celle-ci est immédiatement activée.
Mise en oeuvre
Paramètre des actions
La case Résidente de l'action doit être cochée. Voir le fichier paramètres des actions.
Fin du programme qui traite l'action.
Le programme qui traite l'action doit renvoyer le résultat, éventuellement écrire dans le fichier journal, puis enchaîner au programme XwebServices.dhop.
Pour assurer la compatibilité avec l'ancien mode de fonctionnement il est conseillé d'écrire le code de la manière suivante (les lignes en gras sont celles qui doivent être ajoutées pour les services web écrits dans les versions antérieures à la version 6.2) :
if IsProgramCalled = FALSE ; l'action est paramétrée Résidente WebServiceReturn(resultat,0) ; ProgramGoto("xwebservices.dhop") endif Pong("WebServiceStatus",0) ; l'action n'est pas résidente Pong("WebServiceResult",resultat) Pong("WebServiceVersion",MaVersion) programexit
Paramétrage de la taille du pool des services web
Par défaut, le système garde 10 tâches dans le pool.
Pour changer cette valeur, ajoutez, dans le chapitre System du fichier Divalto.Ini, la clé :
WebServicesSizePool=nombre_de_tâches
Attention, la modification doit être faite dans la base de registre globale à l'ordinateur.
Journalisation
Dans le mode non résident, Xwebservices.dhop écrit dans le journal après chaque action, la date et l'heure d'exécution de l'action, ainsi que sa durée.
Dans le mode résident, Xwebservices.dhop ne récupère plus la main après l'exécution de l'action (en effet, dans ce mode, celle-ci est exécutée par un programGoto et non plus un programCall). Il convient donc au programme qui gère l'action de journaliser lui-même s'il le désire.
Pour cela :
Il devra déclarer le module XwebServices.Dhop et faire appel à la fonction de journalisation WriteLogFile
Exemple
Module "Xwebservice.dhop" TempsTic = wingetTickCount - T0 ;T0 est initialisé au début du main t0 = winGetTickCount Temps = TempsTic/1000 WriteLogFile(0,"Exécution de l'action Mon Action v1.1 en " & nospaces(temps) & " secondes")
Exemple de service Web Diva
;____________________________________________________________________ ;Description : ; Service Web pour quantité en stock pour une référence article ;____________________________________________________________________ define MaVersion = "6.1 " module "pmstock.dhop" 1 ParamEntree S 1 dos 3,0 1 ref 25 1 stock 12,D2 main ; récupération des paramètres d'entrée PingReceive("WebServiceParameters",ParamEntree) Dos = hmpseek(ParamEntree,"dos",998) ; Dossier par défaut 998 Ref = hmpseek(ParamEntree,"reference","") ; calcul du stock stock = interro_stock(dos,ref) ; réponse if IsProgramCalled = FALSE ; l'action est paramétrée Résidente WebServiceReturn(stock,0) ProgramGoto("xwebservices.dhop") endif Pong("WebServiceStatus",0) ; l'action n'est pas résidente Pong("WebServiceResult",stock) Pong("WebServiceVersion",MaVersion) programexit
Installation du serveur Web
Les services Web Diva s'appuient sur la technologie .NET de Microsoft.
La mise en œuvre nécessite donc le serveur IIS (Internet Information Services) de Microsoft. Elle nécessite également l'installation du FrameWork .Net sur ce serveur.
Pour le détail de l'installation voir le chapitre « Installation Harmony Web » dans l'installation et paramétrage d'Harmony.
Client Diva d'un service Web Diva
La fonction WebServiceDivaExecute permet d'exécuter un service Web Diva.
Elle comporte 4 paramètres :
L'URL de la page WebServiceDiva.asmx du serveur Web
Le paramètre <action>
Les paramètres d'entrée du service
Le paramètre de retour renvoyé par l'action
Elle renvoie un compte-rendu :
0 si OK
En cas d 'erreur, le paramètre retour contient habituellement un message d'erreur en clair.
Confidentialité
Les paramètres d'entrée et de retour peuvent être cryptés pour assurer la confidentialité des informations transmises.
Exemple de client Diva d'un service Web Diva
;____________________________________________________________________ ;Description : ; Demande la quantité en stock pour une référence article à ; un service Web Diva ;____________________________________________________________________ 1 Url S 1 St X 1 Retour S 1 Stock 12,D2 main ; Appel du service Url = "http://www.divalto.fr/Ws/WebServiceDiva.asmx" St = WebServiceDivaExecute(Url, \ "<action>Stock", \ "<dos>998<reference>ALB0001", \ Retour) ; en cas d'erreur Retour contient le message if St MessageBox(binhexa(stx(St)) & " " & Retour ," ") else Stock = Retour endif ProgramExit
Programmation service web ou webhook : paramètre en entrée et sortie
L’exemple ci-dessous illustre la récupération en entrée dans un programme Diva des paramètres pour un service web ou un webhook, et les paramètres de retour
;___________________________________________________________________________ ;Description : Envoie la quantité en stock pour une référence article ;___________________________________________________________________________ module "ysystemex.dhop" module "xwebservices.dhop" public record ddsys.dhsd Action Bal define Vers = "2023" 1 WebServiceAction 64 1 ParamAction 256 1 ParamEntree S 1 ParamEntreeUnicode S 1 WebServiceWebhook 40 = " " 1 WebServiceWebhookCode 256 = " " 1 WebServiceWebhookParamHMP 256 = " " 1 commProvenantDuFichierXbalwebHook 75 = " " 1 cappelProvenantDuFichierXbalwebHook 16 = " " 1 moderaw 3 1 WebServiceWebhookRaw S 1 WebServiceWebhookBody S 1 WebServiceWebhookHeaders S 1 WebServiceWebhookContentType 256 1 WebServiceWebhookParamsRaw s 1 WebServiceWebhookEncodingType 256 1 WebServiceTypeTransport 10 1 WebServiceCommAction 256 1 paramsortie S 1 paramsortiehh S 1 CodeHttpResponse 4,0 1 dos 3,0 1 ref 25 1 stock 12,D2 1 carreste L 1 szAuthorization 4096 procedure RecupererLesParametresEnEntree beginp ; récupération des paramètres d'entrée PingReceive("WebServiceParameters",ParamEntree) ParamEntree = Fromutf8toAnsi(left(ParamEntree),carreste,0) PingReceive("WebServiceParametersUnicode",ParamEntreeUnicode) ;idem en unicode mais je sais pas trop a quoi ca peut servir en diva PingReceive("WebServiceAction",WebServiceAction) ; nom de l'action exemple "STOCK" PingReceive("WebServiceTypeTransport",WebServiceTypeTransport) ;type de service contenant le texte "soap","rest","webhook" PingReceive("WebServiceWebhook" ,WebServiceWebhook ) ;numero du webhook exemple F856B712803445A39E098456442C1EDC0C050A0C PingReceive("WebServiceWebhookCode" ,WebServiceWebhookCode) ; la suite apres les 40 caracteres du webhook exemple F856B712803445A39E098456442C1EDC0C050A0Ctoto => on récupere "toto" (tel qu'il et écrit donc avec la case) ;infos provenant de la fiche webhook qui est dans le fichier xbalwebhook.dhfi/dhfd PingReceive("WebServiceWebhookParamHMP" ,WebServiceWebhookParamHMP ) ;champ parametre hmp PingReceive("WebServiceWebhookComm" ,commProvenantDuFichierXbalwebHook ) ;champ commentaire par exemple on peut le mettre dans du debug pour faire une trace PingReceive("WebServiceWebhookCodeAppelant",cappelProvenantDuFichierXbalwebHook) ;champ code d'appel , par exemple on peut y mettre un nom de ste ;infos provenant de la fiche ACTION qui est dans le fichier xbal.dhfi/dhfd PingReceive("WebServiceParamAction",ParamAction) ;param de l'action attention ne pas confondre avec WebServiceParameters PingReceive("WebServiceCommAction,",WebServiceCommAction) ;commentaire de la fiche action , pour mettre dans du debug par exemple, ne pas confondre avec WebServiceWebhookComm PingReceive("WebServiceWebhookContentType" ,WebServicewebhookContentType) ;exemple "application/json" PingReceive("WebServiceWebhookEncodingType",WebServiceWebhookEncodingType) ;type d'encodage en general il contiens "UTF-8" ay milleu du texte donc faire string("UTF-8") et a= "UTF-8" PingReceive("WebServiceWebhookBody" , WebServiceWebhookBody) ;c'est le body tel qu'on le recoit sans aucune transformation WebServiceWebhookBody= Fromutf8toAnsi(left(WebServiceWebhookBody),carreste,0) PingReceive("WebServiceWebhookHeaders" , WebServiceWebhookHeaders) ;entetes au format hmp valeur etc WebServiceWebhookHeaders= Fromutf8toAnsi(left(WebServiceWebhookHeaders),carreste,0) PingReceive("WebServiceWebhookRaw" ,WebServiceWebhookRaw) ;c'es un flag a 1 pour dire que c'est pas un format classique et qu'il faut aller voir webhookbody PingReceive("WebServiceWebhookParamsRaw" ,WebServiceWebhookParamsRaw) ;reencodage du body mais au format hmp plus facile a traiter que le json WebServiceWebhookParamsRaw= Fromutf8toAnsi(left(WebServiceWebhookParamsRaw),carreste,0) ;exemple pour lire les paramètres de la commande service web Dos = hmpseek(ParamEntree,"dos",998) Ref = hmpseek(ParamEntree,"reference","") ;j'ai fait deux service webhook et dans les parametres de mon service xbal ;webhook , j'ai mis <moderaw>1 dan l'un et <moderaw>0 dans l'autre ;c'est juste pour voir comment on peut activer ou pas des options dans un service diva ;de type webhook par exemple moderaw = hmpseek(WebServiceWebhookParamHMP,"moderaw","") ;on peut aussi lire les headers de la requête web d'origine if WebServiceWebhookHeaders <> " " szAuthorization = hmpseek(WebServiceWebhookHeaders,"Authorization","") endif endp procedure EnvoyerReponse beginp ;exemple de retour ;on a fait 2 code de webhook , dans le premier on a mis le flag 1 et dans l'autre webhook 0 ;juste pour tester les 2 types de reponses d'un webhook if val(moderaw) = 0 paramsortie = stock & " éèà ParamEntree=" &left(ParamEntree) & \ " webhookrecu=" & left(WebServiceWebhook) & \ " webhookcode=" & left(WebServiceWebhookCode) & \ " webhookparamhmp=" & left(WebServiceWebhookParamHMP) & \ " webhookcom=" & left(commProvenantDuFichierXbalwebHook) & \ " codeappellant=" & left(cappelProvenantDuFichierXbalwebHook) & \ " ContentType=" & left(WebServicewebhookContentType) & \ " cappelProvenantDuFichierXbalwebHook=" & left(WebServiceWebhookRaw) & \ " body=" & left(WebServiceWebhookBody) & \ " reincodagebodyenhmp" & left(WebServiceWebhookParamsRaw) & \ " headers=" & left(WebServiceWebhookHeaders) paramsortie = FromAnsitoutf8(paramsortie) Pong("WebServiceResultContentType","") Pong("WebServiceResultHeaders","") CodeHttpResponse = 0 ; la valeur par defaut 0 indique que c'est le service web qui va mettre le bon code par exemple 200 si ok et 400 si erreur ;la liste est dans https://fr.wikipedia.org/wiki/Liste_des_codes_HTTP else paramsortie = '{ "test":"xxx","essai":"libre éàé' & left(szAuthorization) & '" }' paramsortie = FromAnsitoutf8(paramsortie) Pong("WebServiceResultContentType","application/json") Pong("WebServiceResultUTF8","1") ;code en utf8 ou pas, c'est pas simple car postman reconvertie ! ce qui fait que pour postman il faudrait mettre 0 ici ;en hmp on peut utiliser valeur ou bien $03 motcle $04 valeur ;mais faut pas mixer les deux mode , c'est soit toujours < > ou soit toujours $03 $04 ;le mode $03 $04 est mieux car il permet de passer les caractères < > dans le champ valeur paramsortiehh = $03 & "test_de_headers" & $04 & "10" & $03 & "code_secret_a_moi" & $04 & "simple testéè" ;attention IL NE DOIT PAS Y AVOIR DE BLANC DANS LE NOM D'UN HEADERS, c'est une norme web paramsortiehh = left(paramsortiehh ) & $03 & "Authorization" & $04 & "Bearer ExYYyd8YsaOOT7XuZRHiULleAJsDK4StFvh6QWbbca_ro45GQtk38gkeOF14Uzv03LD4ppZoDlOjEUbEVJ/HPXc/c9kYygaCuABB2zM2c6mdpAbNgnkNE0CSX22fGvlf" paramsortiehh = FromAnsitoutf8(paramsortiehh) Pong("WebServiceResultHeaders",left(paramsortiehh)) ;Pong("WebServiceResultHeadersContent",left(paramsortiehh)) CodeHttpResponse = 402 ;exemple c'est juste pour test , ca renvoi le code "payment required" voir les codes https://fr.wikipedia.org/wiki/Liste_des_codes_HTTP endif ; réponse Pong("WebServiceStatus",0) ;erreur ou pas du programme Pong("WebServiceResult",left(paramsortie)) ;la reponse Pong("WebServiceVersion",Vers) ;version => je sais pas a quoi ca sert mais c'est comme ca Pong("WebServiceResultCodeHTTP",CodeHttpResponse ) ;code de reponse http ; 0 pour dire "prendre le code par defaut" ou nnn pour fixer un code endp exemple d'utilisation main RecupererLesParametresEnEntree stock = 457 ; calcul du stock EnvoyerReponse programexit