Recherche sur le blog

lundi 1 décembre 2014

[WD19] Utiliser l'API Exchange Web Services (II)

Il y a quelques mois nous avions vu comment utiliser l'API Exchange Web Services 2.0 depuis Windev. Grâce aux bibliothèques .NET fournies il est possible d'interroger un serveur Exchange et de récupérer les e-mails d'un utilisateur. Nous avons fait l'expérience en créant une petite fonction qui récupère 10 objets à la fois dans la boite de réception de l'utilisateur, et ce en travaillant avec la notion d'offset, ce qui permet à terme d'effectuer des opérations de pagination (ex : l'utilisateur appuie sur un bouton pour afficher la deuxième page).

Télécharger les bibliothèques et les importer

L'API est fournie par Microsoft et peut être téléchargée sur le site officiel à l'adresse suivante : http://www.microsoft.com/en-us/.../details.aspx?id=35371. Sélectionnez la version qui convient (32 ou 64 bits) puis installez-là sur votre poste de développement. Les DLL sont alors disponibles dans le répertoire %ProgramFiles%\Microsoft\Exchange\Web Services\2.0. Importez-les dans votre projet Windev.

Recherche avec pagination

Dans l'exemple qui suit, nous allons effectuer une récupération de 10 éléments en modifiant à chaque fois l'offset. Nous nous basons sur le tutoriel proposé sur MSDN qui explique comment fonctionne cette méthode. Nous avons alors repris la procédure d'exemple en fin de page mais nous avons fait une croix sur l' "ancre" qui permet de déterminer si un élément a changé de place ou non.


Il est évidemment important d'allouer un objet Credentials pour permettre la connexion à chaque requête. Le Web Service EWS étant stateless, la connexion n'est pas constante et chaque requête est traitée indépendamment des autres. Avant toute chose, il faut donc instancier un objet global de type ExchangeService, qu'on pourra réutiliser dans chaque fenêtre. Dans le code qui suit, l'objet fait plutôt partie d'une classe qu'on pourra déclarer dans la section "initialisation du projet".


Voici ce qui a été réalisé :
  • Instanciation de la classe ExchangeService. Le constructeur reçoit en paramètre le numéro de version Exchange qui doit correspondre à celui utilisé sur le serveur, sinon les requêtes ne seront pas toujours bien gérées (MSDN#FF597939).
  • On se connecte en utilisant le nom d'utilisateur, le mot de passe et le domaine (en allouant une nouvelle instance d'un objet de type WebCredentials).
  • La fonction "AutodiscoverUrl()" permet de localiser le fichier Exchange.asmx sur le serveur pour pouvoir envoyer les futures requêtes. On obtient alors l'URL du "point d'entrée" (endpoint) du web service.
             
Si la connexion a abouti il faut ensuite réaliser ces opérations :


Dans l'ordre, voici ce qui a été fait :
  • On crée un nouvel objet de type ItemView permettant de stocker un nombre d'objet défini par la variable "iPageSize". L'offset - stocké dans la variable "iOffset" - indique l'endroit à partir duquel on souhaite récupérer les informations (de base 0 pour commencer au début). Il devra être progressivement modifié pour récupérer les éléments suivants.
  • On initialise l'ensemble des propriétés à récupérer. Dans ce cas-ci, on récupère simplement l'ID mais on peut imaginer récupérer la date/heure de réception ou le sujet. A partir de cet instant on peut utiliser la syntaxe suivante : maVue.PropertySet.Add(xxxxx). A noter que la fonction FindItems() ne récupère pas les adresses des destinataires ou de l'expéditeur.
  • On ajoute une condition de tri : maVue.OrderBy.Add(champ, ordre du tri). Ici, on souhaite trier sur la date/heure de réception (ItemSchema.DateTimeReceived) de manière descendante (la plus récente d'abord soit SortDirection.Descending).
  • On indique la méthode de recherche.
          
Pourquoi ne pas avoir indiqué d'autres propriétés dans le constructeur de la classe PropertySet ? Si on souhaite en rajouter d'autres, on peut se servir de la méthode Add() car le second constructeur de la classe PropertySet demande une collection d'objets. En .NET, lorsqu'on indique plusieurs objets à la suite, il considère cela comme un tableau d'objets ou une collection IEnumerable, et reconnait quel constructeur doit être appelé. Mais à ce stade Windev n'est pas capable d'effectuer la conversion de types.

On entre alors dans le vif du sujet : la récupération des e-mails.


Voici ce qu'on a réalisé dans cette étape (le tout étant englobé dans une boucle) :
  • On a englobé le code dans une boucle qui teste "bMoreItems".  Tant que cette variable est à "true", on continue le traitement. Lorsqu'elle vaut "false", on sort de la boucle.
  • A chaque tour de boucle on initialise l'objet de type 'FindItemsResults' (à déclarer comme tel en début de fonction) en appelant simplement la fonction FindItems() qui reçoit en paramètre le dossier (ex : WellKnownFolderName.Inbox) ainsi que la vue qui a été précédemment paramétrée. Seul l'offset changera au cours de l'opération.
  • S'il y a d'autres résultats alors on va augmenter l'offset pour le prochain tour de boucle en rajoutant à celui-ci la taille d'une page (ici, on ajoute donc 10). Si on avait utilisé le système d'ancre, il aurait fallu récupérer à chaque fois un objet de plus pour permettre de déterminer s'il y avait eu un changement entre deux sets de résultats.
  • Ensuite on charge l'ensemble des propriétés de "première classe", il s'agit notamment des champs sujet, date/heure réception, expéditeur, destinataire(s), etc. Dans ce cas s'il y a 10 objets récupérés on charge en mémoire les propriétés de ceux-ci.
              
Pour parcourir la collection il faut utiliser une boucle de type POUR TOUT. On arrête cette boucle lorsqu'on a atteint le nombre d'objets retourné. Pour en sortir, il faudra le faire de force avec le mot-clé adéquat. On y traite les e-mails un par un et là, c'est à vous de décider ce que vous faites. Dans l'exemple ci-dessous, on enregistre simplement dans des membres d'une classe. On peut imaginer d'ajouter chaque élément dans un champ Table.


Ce qu'il faut faire :
  • Initialiser la variable de comptage à 0.
  • Initialiser le nombre maximum d'objets à afficher.
  • Traiter chacun des objets de la collection monResultset.Items.
  • Incrémenter la variable d'itération.
  • Sortir lorsqu'elle est égale à la variable qui contient le nombre de résultats à afficher.
            
Contraintes rencontrées

Lorsqu'on utilise une API .NET, on peut faire face à certains soucis...
  • Windev ne prend pas en charge les tableaux d'objets en .NET. Dans notre cas on ne peut pas écrire "clDrFindResults.Items[x]". 
  • Certaines fonctions comme FindItems.Items.First() ou Last() tentent d'effectuer des copies d'objet. Cela n'est pas géré par Windev et donc les fonctions ne peuvent pas être utilisées telles quelles.
  • La conversion d'objets pose problème dans le cas des constructeurs, comme c'est le cas lorsqu'on effectue une allocation d'un objet de la classe PropertySet. Dans ce cas il faut trouver une alternative...
  • Certains objets doivent être convertis en chaine pour l'affichage avec les méthodes ToString(). En général, cela se fait automatiquement en .NET, sauf dans certains cas bien précis.
            
Bon développement à tous !

Aucun commentaire: