﻿<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tag MessageContext - Constellation</title>
	<atom:link href="https://developer.myconstellation.io/tag/messagecontext/feed/" rel="self" type="application/rss+xml" />
	<link>https://developer.myconstellation.io/tag/messagecontext/</link>
	<description>Votre plateforme d&#039;interconnexion</description>
	<lastBuildDate>Mon, 30 Apr 2018 12:40:00 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.0.11</generator>

<image>
	<url>https://developer.myconstellation.io/wp-content/uploads/2016/02/256x256-e1457476015859.png</url>
	<title>Tag MessageContext - Constellation</title>
	<link>https://developer.myconstellation.io/tag/messagecontext/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Nouvelle librairie Constellation pour Arduino / ESP8266 en version 2.0</title>
		<link>https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/</link>
					<comments>https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/#comments</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Tue, 13 Sep 2016 13:20:38 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[Messaging]]></category>
		<category><![CDATA[Message]]></category>
		<category><![CDATA[Console]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<category><![CDATA[MessageContext]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[PurgeStateObject]]></category>
		<category><![CDATA[StateObjectLink]]></category>
		<category><![CDATA[PackageDescriptor]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Virtuel]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Subscribe]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[Arduino]]></category>
		<category><![CDATA[PushStateObject]]></category>
		<category><![CDATA[ESP8266]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[ESP]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2546</guid>

					<description><![CDATA[<p>J’ai le plaisir de  vous annoncer l’arrivée de la nouvelle libraire Constellation pour Arduino/ESP en version 2.0. Cette nouvelle version amène beaucoup de nouveautés que je vous propose de découvrir dans cet article. La librairie a été testé avec succès</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/">Nouvelle librairie Constellation pour Arduino / ESP8266 en version 2.0</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>J’ai le plaisir de  vous annoncer l’arrivée de la nouvelle libraire Constellation pour Arduino/ESP en version 2.0.</p>
<p>Cette nouvelle version amène beaucoup de nouveautés que je vous propose de découvrir dans cet article. La librairie a été testé avec succès sur différentes cartes animées par un ESP8266 (ESP-01, 05, 07 et D1 Mini) ainsi qu’un Arduino/Genuino MKR1000.</p>
<p>Pour la mise à jour, téléchargez la libraire ci-dessous et dézippez les fichiers dans le dossier “Constellation” dans votre répertoire de libraire Arduino.</p>

<p><u>Attention</u> : cette version 2.x de la librairie Constellation pour Arduino/ESP nécessite la version <a href="/constellation-platform/changelog/#05092016_Update_Server_18116249">1.8.1.16249</a> ou plus récente du serveur Constellation pour fonctionner correctement. Pour mettre à jour votre plateforme Constellation, lancez le <a href="/downloads/">Web Platform Installer</a>.</p>
<h3>Réception de message et StateObject “asynchrone”</h3>
<p>Il s’agit d’une grosse évolution par rapport à la version 1.x. Pour “récupérer” du serveur Constellation les messages à destination de votre package virtuel ou les StateObjects pour lequel votre package (virtuel) s’est abonné, il faut invoquer les actions “<a href="/client-api/rest-api/interface-rest-constellation/#Recevoir_des_messages">GetMessages</a>” et “<a href="/client-api/rest-api/interface-rest-constellation/#Subscribe">GetStateObjects</a>” sur l’interface REST.</p>
<p>Ces méthodes supportent le “long-polling” c’est à dire qu’elles mettent en attente la requête tant qu’il n’y a pas de messages ou StateObjects à retourner avec la notion de timeout (par défaut 60 secondes).</p>
<p>Le problème sur les versions 1.x de la libraire Arduino est que le client HTTP est “synchrone”, c’est à dire qu’il envoi la requête HTTP et attend la réponse du serveur pour traitement ce qui est incompatible avec du long-polling car cela bloquerait le code de l’Arduino. De ce fait, les anciennes versions spécifiées le “timeout” de ces requêtes à 1 seconde.</p>
<p>Ainsi jusqu’à maintenant, l’interrogation des messages et SO pouvaient bloquer jusqu’à 2 secondes votre Arduino (1 seconde pour le GetMessage et 1 seconde pour le GetStateObject) et engendrait donc 1 requêtes HTTP toutes les secondes entre votre ESP/Arduino et le serveur Constellation.</p>
<p>Dans cette nouvelle version, la librairie utilisent 3 clients HTTP différents : un pour toutes les requêtes synchrones, un pour la réception de message (<em>GetMessage</em>) et un pour la réception des StateObjects (<em>GetStateObjects</em>).</p>
<p>Le client synchrone est donc toujours disponible et il n’y a aucun blocage, aucune attente pour la réception de message et de SO. De plus il n’y a plus besoin de “poller” ou “flooder” le serveur d’une requête toute les secondes, en réactivant le long-polling le 2ème et 3ème client HTTP, on lance une requête toutes les minutes (60 sec par défaut) dans l’attente de message et SO.</p>
<p>De ce fait, il y a quelques modifications à apporter dans votre code !</p>
<p>Premièrement, vous ne devez plus passer la référence de votre client réseau mais plutôt spécifier le type de votre client dans le template de la classe Constellation. Par exemple, si vous utilisez un ESP8266 ou un Arduino MKR1000, vous utiliserez la classe “WifiClient “” :</p>
<p></p><pre class="crayon-plain-tag">/* Create the Constellation client */
Constellation&lt;WiFiClient&gt; constellation("constellation.monserveur.com", 8088, "MyVirtualSentine", "MyPackage", "MyAccessKey123!");</pre><p></p>
<p>Ensuite, il n’y a plus besoin d’invoquer la méthode “poll” dans votre boucle principale avec un timer, vous devez tout simplement appeler la méthode “loop” autant de fois que vous voulez :</p>
<p></p><pre class="crayon-plain-tag">void loop(void) {
  // Process incoming message &amp; StateObject updates
  constellation.loop();
}</pre><p></p>
<p>Cette méthode vérifie en fait si il y a eu une réponse sur le client utilisé pour la réception de message et sur le client pour la réception de SO afin de les dispatcher dans votre code.</p>
<h3>Support du PackageDescriptor</h3>
<p>Autre nouveauté majeure pour cette version 2, le support du “Package Descriptor”.</p>
<p>Pour rappel le “Package Descriptor” est un objet envoyé par un package au serveur pour décrire ses StateObjects et ses MessageCallbacks exposés par le package.</p>
<p>Le MessageCallback Explorer de la Console Constellation s’appuie sur le “Package Descriptor” de chaque package pour lister chaque MessageCallback avec un formulaire de test. Sans cette description cela serait impossible !</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image.png"><img class="colorbox-2546"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageCallback Explorer" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb.png" alt="MessageCallback Explorer" width="350" height="168" border="0" /></a></p>
<p>Les versions 1.x ne supportaient pas “Package Descriptor”, de ce fait il n’était pas possible d’explorer/découvrir les MessageCallbacks d’un package Arduino/ESP. Vous devez nécessairement connaitre par vous même les MC exposés par le package et le type des StateObjects qu’il pouvait publier.</p>
<p>Avec la version 2.0, l’Arduino/ESP envoie au serveur la description des MC exposés et des types utilisés par les SO et arguments des MC.</p>
<p>Dans la suite de cet article, vous découvrirez comment ajouter des types dans la description de votre package, mais n’oubliez jamais d’envoyer votre “Package Descriptor” en invoquant la méthode “declarePackageDescriptor”, typiquement une fois votre code Arduino initialisé (par exemple à la fin de la méthode <em>setup()</em>) :</p>
<p></p><pre class="crayon-plain-tag">// Declare the package descriptor
constellation.declarePackageDescriptor();</pre><p></p>
<h3>Amélioration du PushStateObject</h3>
<p>La méthode “PushStateObject” permet de publier un StateObject sur le serveur Constellation.</p>
<p>Tout d’abord la méthode expose des surcharges vous permettant de spécifier comme “value” de votre SO des int, uint, double, float, long et bool et supporte en paramètre optionnel le “lifetime”, c’st à dire la durée en seconde de “vie” de votre StateObject avant d’être considéré comme expiré.</p>
<p></p><pre class="crayon-plain-tag">// Dummy data
uint16_t lux = 123;

// Push a simple type on Constellation 
constellation.pushStateObject("DemoLux", lux);  

// Push a simple type on Constellation with lifetime of 20 seconds
constellation.pushStateObject("DemoLux", lux, 20);</pre><p></p>
<p>Vous pouvez toujours publier des StateObjects dont la valeur (value) est un objet complexe (formaté en JSON).</p>
<p>Le JSON peut être formaté sous forme d’une chaine de caractère avec la méthode “stringFormat” :</p>
<p></p><pre class="crayon-plain-tag">// Push a complex object on Constellation with stringFormat
constellation.pushStateObject("DemoLux", stringFormat("{ 'Lux':%d, 'Broadband':%d, 'IR':%d }", lux, full, ir));</pre><p></p>
<p>Vous pouvez également définir votre propre type pour ce StateObject, par exemple nommons cet objet “MyLuxData” :</p>
<p></p><pre class="crayon-plain-tag">constellation.pushStateObject("DemoLux", stringFormat("{ 'Lux':%d, 'Broadband':%d, 'IR':%d }", lux, full, ir), "MyLuxData");</pre><p></p>
<p>Sans oublier d’ajouter ce type “personnalisé” dans le “package descriptor”. Par exemple, dans le “setup()” et avant de faire un “declarePackageDescriptor”, on aurait décrit “MyLuxData” de la façon suivante :</p>
<p></p><pre class="crayon-plain-tag">constellation.addStateObjectType("MyLuxData", TypeDescriptor().setDescription("MyLuxData demo").addProperty("Broadband", "System.Int32").addProperty("IR", "System.Int32").addProperty("Lux", "System.Int32"));</pre><p></p>
<p>Pour finir, vous pouvez toujours publier un StateObject en construisant la valeur dans un objet JsonObject de façon suivante :</p>
<p></p><pre class="crayon-plain-tag">// Push a complex object on Constellation with JsonObject
const int BUFFER_SIZE = JSON_OBJECT_SIZE(5);
StaticJsonBuffer&lt;BUFFER_SIZE&gt; jsonBuffer;
JsonObject&amp; myStateObject = jsonBuffer.createObject();
myStateObject["Lux"] = lux;
myStateObject["Broadband"] = full;
myStateObject["IR"] = ir;
constellation.pushStateObject("DemoLux", myStateObject);</pre><p></p>
<p>Dans les surcharges de cette méthode, vous pouvez également spécifier le type de votre StateObject et/ou sa durée de vie :</p>
<p></p><pre class="crayon-plain-tag">constellation.pushStateObject("DemoLux", myStateObject, "MyLuxData", 20);</pre><p></p>
<p>Pour finir, nouveauté de la librairie 2.0, vous pouvez également spécifier des “meta-données” à vos StateObjects. Par exemple :</p>
<p></p><pre class="crayon-plain-tag">// Ajout de metadatas au StateObject
JsonObject&amp; metadatas = jsonBuffer.createObject();
metadatas["ChipId"] = ESP.getChipId();
metadatas["Timestamp"] = millis();
constellation.pushStateObject("DemoLux", myStateObject, "MyStateObject", 20, &amp;metadatas);</pre><p></p>
<h3>Les StateObjectLinks</h3>
<p>En version 1.x de la librairie Arduino, vous pouvez :</p>
<ul>
<li>interroger des StateObjects de la Constellation en invoquant la méthode “requestStateObjects” qui vous retourne les StateObjects à l’instant T correspondant à votre requête :</li>
</ul>
<p></p><pre class="crayon-plain-tag">// Example : print the all SO's value named "/intelcpu/0/load/0" and produced by the "HWMonitor" package (on all sentinels)
JsonArray&amp; cpus = constellation.requestStateObjects("*", "HWMonitor", "/intelcpu/0/load/0");
for(int i=0; i &lt; cpus.size(); i++) { 
  constellation.writeInfo("CPU on %s is currently %d %", cpus[i]["SentinelName"].asString(), cpus[i]["Value"]["Value"].as&lt;float&gt;());
}</pre><p></p>
<ul>
<li>vous abonnez aux mises à jour des StateObjects pour être notifié en temps réel des que les SO changent :</li>
</ul>
<p></p><pre class="crayon-plain-tag">// set a StateObject update callback and subscribe to SO
constellation.setStateObjectUpdateCallback([] (JsonObject&amp; so) {
constellation.writeInfo("StateObject updated ! StateObject name = %s", so["Name"].asString()); 
});
// Subscribe to SO named "/intelcpu/0/load/0" and produced by the "HWMonitor" package (on all sentinels)
constellation.subscribeToStateObjects("*", "HWMonitor", "/intelcpu/0/load/0");</pre><p></p>
<p>Vous pouvez invoquer plusieurs fois la méthode “subscribeToStateObjects” pour ajouter des abonnements à d’autre StateObjects mais il n’y a qu’un seul callback de réception des SO (défini par la méthode setStateObjectUpdateCallback). C’est à vous de “dispatcher” les SO reçus.</p>
<p>La nouveauté en 2.0 vient de l’ajout de la méthode “registerStateObjectLink” qui vous permet d’associer un callback à un abonnement laissant ainsi à la librairie la charge du “dispatch”.</p>
<p>Par exemple, on peut désormais écrire :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerStateObjectLink("*", "HWMonitor", "/intelcpu/0/load/0", [](JsonObject&amp; so) {
  constellation.writeInfo("CPU on %s is currently %d %", so["SentinelName"].asString(), so["Value"]["Value"].as&lt;float&gt;());
});</pre><p></p>
<p>Ici on enregistre un “StateObject Link” sur tous les SO nommés « /intelcpu/0/load/0 » produits par le package “HWMonitor” de toutes les sentinelles de votre Constellation. Dès qu’un de ces StateObjects changent on exécutera le callback associé, qui ici écrit dans le log un message indiquant la nouvelle valeur du CPU.</p>
<p>Vous bien entendu enregistrer autant de StateObjectLink que vous souhaitez.</p>
<h3>Enregistrement des MessageCallbacks</h3>
<p>Le principe est le même que celui décrit ci-dessus pour les abonnements aux StateObjects.</p>
<p>En version 1.x, on devait définir un callback pour réception de message et invoquer la méthode “subscribeToMessage” :</p>
<p></p><pre class="crayon-plain-tag">// Set callback for all incoming messages
 constellation.setMessageReceiveCallback([](JsonObject&amp; json) { 
   constellation.writeInfo("Message receive ! Message key = %s", json["Key"].asString());     
 }); 
 // Subscribe to message
 constellation.subscribeToMessage();</pre><p></p>
<p>C’était donc à votre charge de “dispatcher” les messages reçus en fonction du “MessageKey”.</p>
<p>Désormais avec la version 2.0, vous pouvez enregistrer un callback pour un “MessageKey” donné. Par exemple :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("HelloWorld",
  [](JsonObject&amp; json) {
    constellation.writeInfo("Hello Constellation !");
 });</pre><p></p>
<p>Dans l’exemple ci-dessous, on ajoute/expose un MessageCallback “HelloWorld” qui écrit dans les logs !</p>
<p>Il n’y donc plus besoin de “dispatcher”, un MessageCallback est donc associé à un “MessageKey” unique et un callback. Il n’y a plus besoin non plus de faire un “subscribeToMessage” (cette méthode est invoquée implicitement par le <em>registerMessageCallback</em>).</p>
<p>De plus cette méthode ajoute implicitement les MessageCallbacks dans le Package Descriptor de sorte que chaque MC soit ainsi référencé dans la Constellation</p>
<p>(console)</p>
<p>Vous pouvez également passer un “MessageCallbackDescriptor” dans l’enregistrement de vos MC pour ajouter une description par exemple :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("HelloWorld",
  MessageCallbackDescriptor().setDescription("Say Hello to Constellation"),
  [](JsonObject&amp; json) {
    constellation.writeInfo("Hello Constellation !");
 });</pre><p></p>
<p>Et même définir les paramètres de vos MC :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("SayHello",
  MessageCallbackDescriptor().setDescription("Say hello !").addParameter("FirstName", "System.String").addParameter("LastName", "System.String"),
  [](JsonObject&amp; json) {
    constellation.writeInfo("Hello %s %s", json["Data"][0].asString(), json["Data"][1].asString()); 
 });</pre><p></p>
<p>Ici on déclare un MC nommé “SayHello” prenant deux paramètres de type String avec un texte de description. Dans la code nous verrons :</p>
<p>(console)</p>
<p>Tout comme les StateObjects, les types des arguments des MC peuvent être des types complexes.</p>
<p>Par exemple enregistrons un MC prenant un seul argument de type “SampleUserData” que nous allons décrire avec la méthode “addMessageCallbackType” comme un objet composé de deux propriétés de type String :</p>
<p></p><pre class="crayon-plain-tag">// Expose a MessageCallback with complex parameter :
constellation.registerMessageCallback("SayHello2",
  MessageCallbackDescriptor().setDescription("Say hello with complex object!").addParameter("User", "SampleUserData"),
  [](JsonObject&amp; json) {
    constellation.writeInfo("Hello %s %s", json["Data"][0]["FirstName"].asString(), json["Data"][0]["LastName"].asString()); 
});  
// and describe the complex parameter "SampleUserData"  
constellation.addMessageCallbackType("SampleUserData", TypeDescriptor().setDescription("This is a smaple user data").addProperty("FirstName", "System.String").addProperty("LastName", "System.String"));</pre><p></p>
<p>Enfin la méthode “registerMessageCallback” accepte également des callbacks prenant en paramètre le “MessageContext” :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("HelloWorld",
  MessageCallbackDescriptor().setDescription("Say Hello to Constellation"),
  [](JsonObject&amp; json, MessageContext ctx) {
    constellation.writeInfo("Message received from %s", ctx.sender.friendlyName);
 });</pre><p></p>
<p>L’objet “MessageContext” est défini de la façon suivante :</p>
<p></p><pre class="crayon-plain-tag">typedef struct {
    const char* sagaId;
    bool isSaga;
    const char* messageKey;
    MessageSender sender;
    ScopeType scope;
} MessageContext;

typedef struct {
    SenderType type;
    const char* friendlyName;
    const char* connectionId;
} MessageSender;</pre><p></p>
<p>Vous pouvez donc récupérer les informations sur l’émetteur (Sender) du message, le scope et l’identifiant de Saga si c’est une saga (isSaga = true).</p>
<h3>Support des Saga (messages avec réponse)</h3>
<p>Une <a href="/concepts/messaging-message-scope-messagecallback-saga/#Les_Sagas">saga</a> est un identifiant unique qu’on affecte à des messages pour les lier entre eux. Cela permet de faire des couples de message “Requête / Réponse”. Une “réponse” étant un message renvoyé à l’émetteur de la requête avec le même identifiant de saga pour que ce dernier puisse l’identifier comme la “réponse” à son message d’origine.</p>
<p>Vous pouvez exposer des MessageCallbacks qui “répondent”, c’est à dire des  MessageCallbacks qui retournent un message de réponse.</p>
<p>Par exemple, exposons un MC pour réaliser des Additions sur un Arduino. Vous enregistrerez un MC “Addition” prenant en parametre deux entiers et qui en retourne un (le résultat) :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("Addition",
  MessageCallbackDescriptor().setDescription("Do addition on this tiny device").addParameter("a", "System.Int32").addParameter("b", "System.Int32").setReturnType("System.Int32"),
  [](JsonObject&amp; json, MessageContext ctx) {        
    int a = json["Data"][0].as&lt;int&gt;();      
    int b = json["Data"][1].as&lt;int&gt;();
    int result = a + b;
    constellation.writeInfo("Addition %d + %d = %d", a, b, result);      
    if(ctx.isSaga) {
      constellation.writeInfo("Doing additoon for %s (sagaId: %s)", ctx.sender.friendlyName, ctx.sagaId);   
    // Return the result :
      constellation.sendResponse&lt;int&gt;(ctx, result);
    }
    else {
      constellation.writeInfo("No saga, no response !");
    }
 });</pre><p></p>
<p>Vous remarquerez dans le “MessageCallbackDescriptor” l’appel de la méthode “setReturnType” pour spécifier le type de retour (et que le fait qu’il s’agit d’un MC acceptant les sagas).</p>
<p>L’envoi de la réponse étant réalisé par la méthode sendReponse. Cette méthode a plusieurs surcharges :</p>
<p></p><pre class="crayon-plain-tag">template&lt;typename T&gt; bool sendResponse(MessageContext context, T data);
bool sendResponse(MessageContext context, const char* data, ...);
bool sendResponse(MessageContext context, JsonObject&amp; data);</pre><p></p>
<p>Notez aussi que vous devriez faire un “sendResponse” si et seulement le message reçu est associé à une saga, c’est à dire que le champs “isSaga” du contexte (MessageContext) est “vrai”. Sinon ca ne sert à rien de répondre <img class="wlEmoticon wlEmoticon-winkingsmile colorbox-2546" style="border-style: none;" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/wlEmoticon-winkingsmile.png" alt="Clignement d'œil" /></p>
<p>Pour finir, cette nouvelle version supporte également l’envoi de message dans une saga. C’est à dire que vous pouvez envoyer un message qui attend une réponse et donc enregistrer un callback de traitement de la réponse.</p>
<p>Par exemple le package “NetworkTools” expose un MC “Ping” permettant de faire un ping. Le package retourne dans la saga un message contenant le temps en milliseconde du ping. On pourrait alors invoquer cette méthode depuis notre Arduino de la façon suivante :</p>
<p></p><pre class="crayon-plain-tag">const char* ip = "192.168.0.10";
// Send message in a saga and attach a callback for response :
constellation.sendMessageWithSaga([](JsonObject&amp; json) {
  constellation.writeInfo("Ping response in %s ms", json["Data"].asString()); 
}, Package, "NetworkTools", "Ping", "[ '%s' ]", ip);</pre><p></p>
<p>Ici on envoi un message au scope “Package” pour atteindre le(x) package(s) “NetworkTools” afin d’invoquer le MessageCallback “Ping” en passant en argument l’IP à pinger. Vous remarquerez qu’on utilise le formatage implicite des arguments.</p>
<p>La méthode n’est pas la traditionnelle “sendMessage” mais “sendMessageWithSaga” qui prend un argument supplémentaire : le callback de traitement de la réponse.</p>
<p>Ainsi quand le package “NetworkTools” répondra, on executera le callback associé qui ici affichera le temps de réponse de notre ping (Data) dans les logs Constellation (writeInfo).</p>
<p>De ce fait, avec cette nouvelle libraire vos Arduino/ESP peuvent invoquer des MC dans sagas pour exploiter la réponse mais également exposer des MC qui retournent des résultats.</p>
<h3>Autres nouveautés</h3>
<p>En vrac, vous disposez maintenant une méthode “purgeStateObjects” permettant de supprimer des StateObjects de votre package.</p>
<p>De plus la méthode “setDebugMode” accepte en argument l’énumération “DebugMode” composée des valeurs suivantes :</p>
<ul>
<li>“Quiet” (mode silencieux, la libraire ne produit aucune trace dans l’interface Serial)</li>
<li>“Normal” (mode par défaut, écrit quelques informations dans l’interface Serial)</li>
<li>“Verbose” (écrit beaucoup d’information dans l’interface Serial comme par exemple les requêtes et réponse HTTP v ers Constellation)</li>
</ul>
<p>Enfin les exemples fournis dans la libraire ont été complètement revus.</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/">Nouvelle librairie Constellation pour Arduino / ESP8266 en version 2.0</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>MessageCallback : Exposer des méthodes Python</title>
		<link>https://developer.myconstellation.io/client-api/python-api/messagecallbacks-exposer-des-methodes-python/</link>
					<comments>https://developer.myconstellation.io/client-api/python-api/messagecallbacks-exposer-des-methodes-python/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Wed, 24 Aug 2016 09:47:40 +0000</pubDate>
				<category><![CDATA[Python API]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[Message]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[MessageContext]]></category>
		<category><![CDATA[PackageDescriptor]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2511</guid>

					<description><![CDATA[<p>Exposer une méthode Pour exposer une méthode Python dans Constellation vous devez tout simplement ajouter le décorateur “Constellation.MessageCallback” sur votre méthode : [crayon-6972d3d53a710188228089/] Ici nous déclarons le MessageCallback “SimpleMessageCallback” sans paramètre ni documentation. Vous pouvez ajouter un ou plusieurs arguments</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/python-api/messagecallbacks-exposer-des-methodes-python/">MessageCallback : Exposer des méthodes Python</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h3>Exposer une méthode</h3>
<p>Pour exposer une méthode Python dans Constellation vous devez tout simplement ajouter le décorateur “<em>Constellation.MessageCallback</em>” sur votre méthode :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def SimpleMessageCallback():
    Constellation.WriteInfo('Hello Python !')</pre><p></p>
<p>Ici nous déclarons le MessageCallback “SimpleMessageCallback” sans paramètre ni documentation.</p>
<p>Vous pouvez ajouter un ou plusieurs arguments à votre MC et utiliser la syntaxe de Python pour commenter vos MC :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def DemoArg(data):
    "Ceci est la description du MessageCallback DemoArg avec 1 argument"
    Constellation.WriteInfo('arg = %s', data)

@Constellation.MessageCallback()
def DemoArgs(a, b, c):
    "Ceci est la description du MessageCallback DemoArgs avec 3 arguments"
    Constellation.WriteInfo(a)
    Constellation.WriteInfo(b)
    Constellation.WriteInfo(c)</pre><p></p>
<p>Le ou les paramètres peuvent être des types simples (string, int, bool, etc..) ou des types (objets) complexes :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def ComplexMessageCallback(data):
    "Ceci est la description du MessageCallback ComplexMessageCallback avec un objet complexe en argument"
    Constellation.WriteInfo(data.A)
    Constellation.WriteInfo(data.B)
    Constellation.WriteInfo(data.C)</pre><p></p>
<p>L’ensemble de ces méthodes déclarées “MessageCallbacks” seront alors référencées dans la Constellation. Vous pouvez les découvrir en interrogeant le Package Descriptor de votre package.</p>
<p>Par exemple, lancez la Console Constellation et rendez-vous dans le “MessageCallback Browser”. Vous aurez la liste de vos méthodes avec la possibilité de les invoquer directement depuis l’interface :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-9.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageCallbacks Explorer" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-8.png" alt="MessageCallbacks Explorer" width="484" height="346" border="0" /></a></p>
<h3>Documenter son MessageCallback</h3>
<h4>Description des MessageCallbacks</h4>
<p>Comme vous l’avez remarqué dans les exemples précédents, nous utilisons la documentation des méthodes de Python :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def Demo():
    "Ceci est la description du MessageCallback !"
    pass</pre><p></p>
<p>La documentation de la méthode est utilisée comme description du MessageCallback :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/08/image-72.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/08/image_thumb-61.png" alt="image" width="350" height="109" border="0" /></a></p>
<p>La description de la méthode peut être écrite sur plusieurs lignes :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def Demo():
    '''
    The first line is brief explanation, which may be completed with 
    a longer one. For instance to discuss about its methods.
    '''
    pass</pre><p></p>
<h4>Description des arguments des MessageCallbacks</h4>
<p><u>Note</u> : la description des arguments est disponible depuis l’API Python 1.8.4.x. Pensez à mettre à jour la référence de votre API par Nuget depuis Visual Studio ou en <a href="/client-api/python-api/developper-avec-le-package-tools-cli/#Mise_a_jour_du_template">mettant à jour le template depuis la CLI</a>.</p>
<p>Si vous regardez attentivement les arguments des MC dans le MessageCallback Explorer, ils sont reconnus comme « System.Object » étant donné que les arguments d&rsquo;une fonction en Python ne sont pas typés.</p>
<p>Pour décrire les paramètres utilisez la syntaxe suivante dans la description du MC :</p>
<p></p><pre class="crayon-plain-tag">:param &lt;type&gt; &lt;name&gt; : &lt;description&gt;</pre><p></p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def Demo(a, b, c):
    '''
    Ceci est un exemple de MC avec 3 parametres

    :param int a: My int value
    :param bool b: My boolean value
    :param string c: My string value
    '''
    Constellation.WriteInfo("a = %s - type: %s" % (a, type(a)))
    Constellation.WriteInfo("b = %s - type: %s" % (b, type(b)))
    Constellation.WriteInfo("c = %s - type: %s" % (c, type(c)))</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-10.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Description des arguments d'un MC en Python" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-9.png" alt="Description des arguments d'un MC en Python" width="484" height="166" border="0" /></a></p>
<p align="left">Ainsi en retournant sur le MC Explorer, chaque argument est correctement typé dans Constellation.</p>
<h4 align="left">Paramètres optionnels avec valeur par défaut</h4>
<p align="left">Vous pouvez également définir que certains paramètres sont optionnels en spécifiant leurs valeurs par défaut avec la syntaxe [default: XXX] :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def DemoOptional(a, b):
    '''
    Ceci est un exemple de MC des paramètres optionnels

    :param int a: My int value [default:10]
    :param bool b: My boolean value [default:true]
    '''
    Constellation.WriteInfo("a = %s" % a)
    Constellation.WriteInfo("b = %s" % b)</pre><p></p>
<p>&nbsp;</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-11.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Arguments optionnels avec valeur par défaut" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-10.png" alt="Arguments optionnels avec valeur par défaut" width="484" height="138" border="0" /></a></p>
<h4>Décrire les arguments de type complexe</h4>
<p>Dans le cas où un MC prend en paramètre un (ou plusieurs) type complexe, il faudra d&rsquo;abord décrie le type dans la méthode « Start ».</p>
<p>Par exemple, enregistrons au démarrage du package (méthode Start), le type “CredentialInfo” :</p>
<p></p><pre class="crayon-plain-tag">Constellation.DescribeMessageCallbackType("CredentialInfo", "Credential information", [
    { 'Name':'Username', 'Type':'string', 'Description': 'The username' },
    { 'Name':'Password', 'Type':'string', 'Description': 'The password' },
])</pre><p></p>
<p>Une fois tous vos types déclarés, il faut publier le “Package Descriptor” de votre package à Constellation par la ligne :</p>
<p></p><pre class="crayon-plain-tag">Constellation.DeclarePackageDescriptor()</pre><p></p>
<p>Nous pouvons maintenant déclarer un MC avec un parametre de type “CredentialInfo”. Par exemple :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def DemoAuth(credential):
    '''
    Demo MC avec avec un paramètre de type complexe

    :param CredentialInfo credential: the credential info
    '''
    Constellation.WriteInfo("User=%s Password=%s" % (credential.Username, credential.Password))</pre><p></p>
<p>Comme vous pourrez le voir dans le MessageCallbacks Explorer, votre méthode Python est correctement décrite ainsi que son paramètre “credential” de type “Credentialnfo”.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-12.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Argument de type complexe" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-11.png" alt="Argument de type complexe" width="484" height="150" border="0" /></a></p>
<p>Notez également que la description du type CredentialInfo est accessible en cliquant sur le type :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-13.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Argument de type complexe" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-12.png" alt="Argument de type complexe" width="484" height="186" border="0" /></a></p>
<h3>Personnaliser le MessageCallback</h3>
<p>Comme pour l’API.NET, par défaut le nom du MessageCallback déclaré dans la Constellation est le nom de votre méthode mais vous pouvez redéfinir le nom exposé dans la Constellation :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback("MySuperName")
def MyInternalMethodName():
    Constellation.WriteInfo("Hello")</pre><p></p>
<p>Aussi vous pouvez “cacher” ce MessageCallback à la Constellation.</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback(False)
def HiddenMessageCallback():
    "Hidden message callback"
    Constellation.WriteInfo("I'm here !!")</pre><p></p>
<p>Tous les packages ou consommateurs de votre Constellation pourront envoyer un message “HiddenMessageCallback” à votre package Python et donc invoquer votre méthode mais celle-ci ne sera pas déclarée dans le “Package  Descriptor”.</p>
<h3>Récupérer le contexte</h3>
<p>Comme avec l’API.NET, vous pouvez récupérer le contexte de réception du message en déclarant comme dernier argument de votre MessageCallback, le paramètre “context”.</p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback("MaMethode") # méthode renommée !
def DemoSeb5(context):
    "Test du contexte"
    Constellation.WriteInfo("Sender : %s" % context.Sender.FriendlyName)
    Constellation.WriteInfo("test sans parametre")</pre><p></p>
<p>Ou avec des paramètres :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def DemoSeb5(a, b, context):
    "Test du contexte avec parametre"
    Constellation.WriteInfo("Sender : %s" % context.Sender.FriendlyName)
    Constellation.WriteInfo("a = %s et b = %s" % (a, b))</pre><p></p>
<p>Il faut juste que le dernier argument soit nommé “context”. Notez qu’il ne fait pas partie de la signature de votre MessageCallback.</p>
<p>Ci-dessus, le 1er exemple est un MessageCallback caché et sans paramètre et le 2ème n’a que deux paramètres “a” et “b”.</p>
<p>L’objet “context” correspondant à la classe “<em>Constellation.Package.MessageContext</em>”. Vous retrouvez les propriétés suivantes :</p>
<ul>
<li>IsSaga : indique si le message reçu appartient à une Saga</li>
<li>SagaId : identifiant de la Saga (si <em>IsSaga = true</em>)</li>
<li>Scope : scope d’envoi du message reçu
<ul>
<li>Type : type du scope (All, Group, Package, Sentinel, Others)</li>
<li>Args : arguments du scope (ex : nom du groupe, du package ou de la sentinelle)</li>
</ul>
</li>
<li>Sender : représente l’émetteur du message
<ul>
<li>ConnectionId : identifiant de connexion unique de l’émetteur</li>
<li>Type : type de l’émetteur (ConsumerHub, ConstellationHub, ConsumerHttp ou ConstellationHttp)</li>
<li>FriendlyName : nom de l’émetteur</li>
</ul>
</li>
</ul>
<h3>Répondre aux Sagas</h3>
<p>Votre méthode peut également retourner une réponse à l’appelant, c’est ce que l’on appelle <a href="/concepts/messaging-message-scope-messagecallback-saga/">une saga</a>. Pour cela vous pouvez spécifier le type de la valeur de retour dans le décorateur de la façon suivante :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback(returnType='System.Boolean')
def DemoSaga(user, password):
    "Test de saga"
    Constellation.WriteInfo("User=%s Password=%s" % (user, password))
    return user == password</pre><p></p>
<p>Cependant il est recommandé d&rsquo;utiliser la description du MC pour spécifier le type de retour avec la syntaxe</p>
<p></p><pre class="crayon-plain-tag">:return &lt;type&gt;: &lt;description&gt;</pre><p></p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def DemoSaga(user, password):
    '''
    Test de saga

    :param string user: The username
    :param string password: The password
    :return bool: if user match
    '''
    Constellation.WriteInfo("User=%s Password=%s" % (user, password))
    return user == password</pre><p></p>
<p>Cela marche également en combinant la récupération du contexte :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def DemoAuth(user, password, context):
    '''
    Test de saga

    :param string user: The username
    :param string password: The password
    :return bool: if user match
    '''
    Constellation.WriteInfo("Sender : %s" % context.Sender.FriendlyName)
    Constellation.WriteInfo("User=%s Password=%s" % (user, password))
    return user == password</pre><p></p>
<p align="left">Par exemple en ouvrant le “Message Callback Explorer” de la Console Constellation vous constaterez que votre MC “DemoAuth” est bien référencé comme retournant un “Booléen” en prenant deux arguments (car l’argument “context” n’est pas pris en compte dans la signature du MC) :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-14.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="Saga" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-13.png" alt="Saga" width="484" height="142" border="0" /></a></p>
<p align="left">En invoquant cette méthode depuis la console, vous recevrez alors la réponse du package, ici un booléen :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/08/image-74.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/08/image_thumb-63.png" alt="image" width="350" height="241" border="0" /></a></p>
<p align="left">Dans les logs, on retrouve bien la trace de l’invocation de notre Saga avec le “contexte” :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/08/image-75.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/08/image_thumb-64.png" alt="image" width="350" height="104" border="0" /></a></p>
<p>(le FriendlyName de la Console Constellation est “<em>Consumer/ControlCenter:&lt;user&gt;</em>”).</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/python-api/messagecallbacks-exposer-des-methodes-python/">MessageCallback : Exposer des méthodes Python</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/python-api/messagecallbacks-exposer-des-methodes-python/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Envoyer des messages &#038; Invoquer des MessageCallbacks</title>
		<link>https://developer.myconstellation.io/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/</link>
					<comments>https://developer.myconstellation.io/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Wed, 16 Mar 2016 16:41:17 +0000</pubDate>
				<category><![CDATA[.NET API]]></category>
		<category><![CDATA[MessageContext]]></category>
		<category><![CDATA[Proxy]]></category>
		<category><![CDATA[SendMessageProxy]]></category>
		<category><![CDATA[MessageScope]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[Messaging]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=1379</guid>

					<description><![CDATA[<p>Avant de suivre la lecture de cet article vous devez avoir compris les concepts de base des MessageCallbacks. Créer un scope Un message Constellation est envoyé à un Scope qui représente le ou les destinataires du message. Un scope Constellation est</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/">Envoyer des messages &#038; Invoquer des MessageCallbacks</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Avant de suivre la lecture de cet article vous devez avoir compris les <a href="/concepts/messaging-message-scope-messagecallback-saga/">concepts de base</a> des MessageCallbacks.</p>
<h3>Créer un scope</h3>
<p>Un message Constellation est envoyé à un Scope qui représente le ou les destinataires du message.</p>
<p>Un scope Constellation est décrit dans l&rsquo;API.NET par la classe “MessageScope”. Vous pouvez créer un scope avec la méthode statique “Create”.</p>
<p>Par exemple pour créer un scope vers les instances du package “MonPackage” de votre Constellation  :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create("MonPackage")</pre><p></p>
<p>Par défaut le type de scope est “Package”. La ligne ci-dessus est donc identique à la ligne :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create(MessageScope.ScopeType.Package, "MonPackage")</pre><p></p>
<p>Si vous souhaitez cibler une instance d’un package en particulier, vous devez spécifier la sentinelle sur laquelle est hébergée le package que vous ciblez :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create("MaSentinelle/MonPackage")</pre><p></p>
<p>Si vous souhaitez cibler plusieurs packages :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create(MessageScope.ScopeType.Package, "MonPackage", "MonAutrePackage", "EncoreUnAutrePackage")</pre><p></p>
<p>Bien entendu vous pouvez donner le nom d’une instance en particulier (sentinelle + package) ou juste le nom du package :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create(MessageScope.ScopeType.Package, "MaSentinelle/MonPackage", "MonAutrePackage")</pre><p></p>
<p>Le scope “Sentinel” permet de cibler tous les packages sur une sentinelle donnée. Vous pouvez définir autant de sentinelle que vous souhaitez :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create(MessageScope.ScopeType.Sentinel, "MaSentinelle", "MonAutreSentinelle")</pre><p></p>
<p>Le scope “Group” permet de cibler les packages qui <a href="/client-api/net-package-api/messagecallbacks/#Sabonner_et_recevoir_les_messages_dun_groupe">sont abonnés à un groupe</a>. Ici créons un scope pour tous les packages membre du groupe “GroupA” :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create(MessageScope.ScopeType.Group, "GroupA")</pre><p></p>
<p>Vous pouvez bien sûr définir autant de groupe dans un scope que vous souhaitez :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create(MessageScope.ScopeType.Group, "GroupA", "GroupB", "GroupC")</pre><p></p>
<p>Enfin vous pouvez créer des scopes pour cibler tous les clients connectés dans votre Constellation (All) ou tout le monde sauf l’émetteur (Others). Dans ces deux cas, il n’y a pas d’argument à spécifier :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create(MessageScope.ScopeType.Others)</pre><p></p>
<h3>Envoyer un message avec le SendMessage</h3>
<p>La méthode de base pour envoyer un message dans Constellation est “<em>PackageHost.SendMessage</em>”.</p>
<p>Vous devez définir trois arguments pour envoyer un message :</p>
<ul>
<li>Le scope (les destinataires de votre message)</li>
<li>La clé du message (MessageKey)</li>
<li>Le contenu du message (Data)</li>
</ul>
<p>Comme vous le savez, on se sert des messages pour invoquer des méthodes d’autre packages. La clé du message est en fait le nom de la méthode (= le MessageCallback) à invoquer.</p>
<p>Prenons pour exemple les MessageCallbacks définis dans <a href="/client-api/net-package-api/messagecallbacks/">l’article précédent</a>.</p>
<p>Pour invoquer le MessageCallback “MyMethod” sans paramètre (Data = null) on pourrait écrire :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.SendMessage(MessageScope.Create("MonPackage"), "MyMethod", null);</pre><p></p>
<p>Pour une méthode avec plusieurs paramètres, ils faut les encapsuler dans un tableau d’objet :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.SendMessage(MessageScope.Create("MonPackage"), "MyMethodWithMultipleParameters", new object[] { "Un String", 123, true });</pre><p></p>
<p>Cela fonctionne aussi avec des objets complexes. Par exemple pour invoquer notre MessageCallback “Logon” :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.SendMessage(MessageScope.Create("MonPackage"), "Logon", new { User = "seb", Password = "seb" });</pre><p></p>
<p>Avec l’API .NET on ne se sert généralement jamais de cette méthode “SendMessage” car vous avez à disposition le “SendMessageProxy” que nous allons découvrir ci-dessous.</p>
<h3>Envoyer un message avec un proxy dynamique</h3>
<p>La classe “SendMessageProxy” est un objet dynamique qui permet d’envoyer un message de la même manière que vous appelez une méthode en programmation .NET.</p>
<p>Pour créer un proxy dynamique vous devez au préalable avoir créer votre scope :</p>
<p></p><pre class="crayon-plain-tag">MessageScope scope = MessageScope.Create("MonPremierPackage");
dynamic proxy = new SendMessageProxy(scope);</pre><p></p>
<p>Pour simplifier le code, vous pouvez utiliser la méthode d’extension “GetProxy()” sur le MessageScope :</p>
<p></p><pre class="crayon-plain-tag">MessageScope scope = MessageScope.Create("MonPremierPackage");
dynamic proxy = scope.GetProxy();</pre><p></p>
<p>Attention, pour accéder aux méthodes d’extension du <em>MessageScope</em> vous devez ajouter le namespace “Constellation.Package” :</p>
<p></p><pre class="crayon-plain-tag">using Constellation.Package;</pre><p></p>
<p>Une fois le proxy  dynamique créé il suffit d’appeler &lsquo;”fictivement” une méthode pour envoyer le message.</p>
<p>Par exemple pour envoyer le message “MyMethod” avec un contenu du vide, on écrira simplement :</p>
<p></p><pre class="crayon-plain-tag">proxy.MyMethod();</pre><p></p>
<p>Si votre message doit contenir plusieurs arguments :</p>
<p></p><pre class="crayon-plain-tag">proxy.MyMethodWithMultipleParameters("Un String", 123, true);</pre><p></p>
<p>Ou encore avec notre MessageCallback “Logon” qui prend en argument un objet complexe :</p>
<p></p><pre class="crayon-plain-tag">proxy.Logon(new { User = "seb", Password = "seb" })</pre><p></p>
<p>Ainsi vous pouvez invoquer un MessageCallback de n’importe quel package de la même façon que vous invoquerez une méthode de votre code .NET. La méthode invoquée est la clé du message et les arguments sont inclus dans le contenu du message.</p>
<p>Bien sûr avec la méthode d’extension vous pouvez faire tout cela en une ligne de code : créer le scope, récupérer le proxy dynamique et envoyer le message :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create("MonPremierPackage").GetProxy().Logon(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Vous avez également à disposition la méthode “<em>CreateMessageProxy</em>” sur le PackageHost. Cette méthode permet de créer un scope et vous retourne le proxy dynamique.</p>
<p>Les deux lignes ci-dessous sont donc identiques :</p>
<p></p><pre class="crayon-plain-tag">dynamic proxy = MessageScope.Create("MonPremierPackage").GetProxy();
dynamic proxy = PackageHost.CreateMessageProxy("MonPremierPackage");</pre><p></p>
<p>De ce fait, pour invoquer nos trois MessageCallbacks, on peut écrire simplement :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.CreateMessageProxy("MonPremierPackage").MyMethod();
PackageHost.CreateMessageProxy("MonPremierPackage").MyMethodWithMultipleParameters("Un String", 123, true);
PackageHost.CreateMessageProxy("MonPremierPackage").Logon(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Tout comme la méthode “MessageScope.Create”, le “CreateMessageProxy” peut créer tout type de scope.</p>
<p>Par exemple, invoquons le MessageCallbacks “MyMessageCallback” avec deux arguments (un string et un datetime) sur tous les packages du groupe A et B de notre Constellation :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.CreateMessageProxy(MessageScope.ScopeType.Group, "GroupA", "GroupB").MyMessageCallback("Mon Argument", DateTime.Now);</pre><p></p>
<h3>Invoquer un MessageCallback avec réponse – Utilisation des Sagas</h3>
<p>Lorsque vous envoyez un message dans un scope vous pouvez ajouter un identifiant de Saga sur ce scope. Cela indiquera au destinataire que vous souhaitez une réponse en retour (<a href="/client-api/net-package-api/messagecallbacks/#Repondre_a_une_saga">plus d’info</a>).</p>
<p>L’identifiant de Saga doit être aléatoire et unique. Vous avez une méthode d’extension “WithSaga” sur un MessageScope vous permettant de définir l’identifiant de la saga (SagaId) avec un GUID :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create("MonPremierPackage").WithSaga();</pre><p></p>
<p>La méthode d’extension vous retourne le MessageScope, vous pouvez donc directement récupérer le proxy dynamique et envoyer votre message :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create("MonPremierPackage").WithSaga().GetProxy().Logon(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Pour la réception des réponses, vous avez une méthode “RegisterSagaResponseCallback” qui permet d’enregistrer la fonction à invoquer lors de la réponse :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.RegisterSagaResponseCallback(sagaId, (reponse) =&gt;
{
      // Response pour la saga "sagaId"
});</pre><p></p>
<p>Pour simplifier le code, vous avez une méthode d’extension “OnSagaResponse” sur un MessageScope qui permet à la fois d’ajouter un identifiant de saga sur le scope (WithSaga) et d’enregistrer la fonction de retour.</p>
<p>De ce fait, vous pouvez en une seule ligne créer votre scope avec saga, définir le code qui sera invoqué à la réception la réponse, récupérer le proxy dynamique et invoquer votre MessageCallback avec ses paramètres :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create("MonPremierPackage").OnSagaResponse((response) =&gt;
{
    // Reponse de la saga
}).GetProxy().Logon(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Comme pour les MessageCallbacks, la méthode de réception d’une réponse d’une saga est invoquée dans un thread dédié dans lequel vous avez accès au contexte du message via la propriété “MessageContext.Current”.</p>
<p>Vous pouvez donc savoir quel est le package qui vous a répondu (<em>Sender</em>) ou encore quel était l’identifiant de la saga utilisée.</p>
<p>De plus, notez que la méthode <em>OnSagaResponse</em> est générique afin de pouvoir définir le type de retour (le cast sera réalisé automatiquement).</p>
<p>On peut donc écrire :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create("MonPremierPackage").OnSagaResponse&lt;bool&gt;((response) =&gt;
{
    PackageHost.WriteInfo("Reponse de {0} pour la saga {1}",                 
        MessageContext.Current.SagaId,
        MessageContext.Current.Sender.FriendlyName);

    PackageHost.WriteInfo(response ? "OK" : "DENIED");

}).GetProxy().Logon(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Notez également que si votre scope cible plusieurs packages (ex : si “MonPremierPackage” est déployé sur plusieurs sentinelles), votre fonction de traitement de la réponse sera invoquée plusieurs fois, pour chaque package qui répondra (car l’identifiant de Saga est le même).</p>
<h3>Utiliser les “Tasks” (awaitable) pour attendre la réponse d’une saga</h3>
<p>C’est une nouveauté de la 1.8 de Constellation. Pour bien comprendre, résumons ce que l’on connait déjà !</p>
<p>Lorsque vous invoquez une méthode sur le proxy dynamique, celui-ci envoie un message dans Constellation où la clé du message est le nom de la méthode invoquée et le contenu du message sont les paramètres de la méthode invoquée.</p>
<p>Ces deux lignes sont donc identiques :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.SendMessage(MessageScope.Create("MonPackage"), "Logon", new { User = "seb", Password = "seb" });
MessageScope.Create("MonPremierPackage").GetProxy().Logon(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Sur la 2ème ligne, vous invoquez dynamiquement la méthode “Logon” sur le <em>SendMessageProxy</em> (créé par la méthode GetProxy()) pour envoyer (<em>PackageHost.SendMessage</em>) le message “Logon”.</p>
<p>Ces deux lignes font donc bien la même chose. Dans les deux cas le message est envoyé dans un scope qui ne porte pas de “SagaId” (donc aucune réponse n’est attendue).</p>
<p>Je rappelle également que vous pouvez créer un scope et récupérer son proxy dynamique directement avec la méthode <em>PackageHost.CreateMessageProxy</em>. On peut donc encore simplifier le code par la ligne :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.CreateMessageProxy("MonPremierPackage").Logon(new { User = "seb", Password = "seb" });</pre><p></p>
<p>D’un point de vue .NET, l’invocation dynamique de notre MessageCallback  “Logon » sur le proxy dynamique ne retourne rien, du moins il retourne “null”.</p>
<p></p><pre class="crayon-plain-tag">object result = PackageHost.CreateMessageProxy("MonPremierPackage").Logon(new { User = "seb", Password = "seb" });
// ici result = null</pre><p></p>
<p>Observez maintenant le code ci-dessous :</p>
<p></p><pre class="crayon-plain-tag">Task&lt;dynamic&gt; reponse = PackageHost.CreateMessageProxy("MonPremierPackage").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Si vous examinez attentivement le MessageCallback que nous invoquons sur le proxy dynamique, on utilise une forme générique : au lieu d’avoir “Logon(xxxxx)”, on a ”Logon<strong>&lt;bool&gt;</strong>(xxxxx)<em>”</em></p>
<p>Le fait de définir un type générique indique au proxy dynamique que vous attendez une réponse et donc qu’il s’agit d’une saga !</p>
<p>Le type générique est le type de réponse que vous attendez. Ici le MessageCallback “Logon” que vous avons écrit dans l’article précédent renvoi un booléen (bool). Vous pouvez utiliser n’importe quel type de base ou types complexes.</p>
<p>Si c’est la réponse est un objet anonyme ou si vous n’avez pas la définition de l’objet de retour dans votre code,  vous pouvez utiliser un “dynamic” (ex <em>Logon<strong>&lt;dynamic&gt;</strong>(xxxx)</em>)<em>.</em></p>
<p>Quoi qu’il en soit il est obligatoire d’invoquer le MessageCallback  en utilisant la syntaxe générique pour que le proxy dynamique ajoute automatiquement un identifiant de saga (<em>WithSaga</em>) lors de l’envoi du message.</p>
<p>Revenons donc à notre appel :</p>
<p></p><pre class="crayon-plain-tag">Task&lt;dynamic&gt; reponse = PackageHost.CreateMessageProxy("MonPremierPackage").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Le proxy dynamique nous retourne une ”Task&lt;dynamic&gt;”, c’est à dire une tache qui se charge d’envoyer et d’attendre la réception de la (première) réponse.</p>
<p>Vous pouvez bloquer le thread appelant jusqu&rsquo;à ce que l&rsquo;opération asynchrone soit terminée,  c’est à dire jusqu’à l’obtention de la réponse :</p>
<p></p><pre class="crayon-plain-tag">Task&lt;dynamic&gt; reponse = PackageHost.CreateMessageProxy("MonPremierPackage").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" });
PackageHost.WriteInfo((bool)reponse.Result ? "OK" : "DENIED");</pre><p></p>
<h4>Ajouter des timeouts</h4>
<p>Comme vous bloquez le thread appelant, prenez garde de mettre des gardes fou car nous n’avez aucune garantie qu’un package va répondre à votre saga. La tache pourrait ne jamais être complétée! Vous devriez donc attendre un certain temps avant de considérer la tache “hors délai”.</p>
<p>Par exemple attendons pendant 3 secondes maximum pour une réponse à notre Saga “Logon” :</p>
<p></p><pre class="crayon-plain-tag">Task&lt;dynamic&gt; reponse = PackageHost.CreateMessageProxy("MonPremierPackage").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" });
if (reponse.Wait(3000) &amp;&amp; reponse.IsCompleted)
{
    PackageHost.WriteInfo((bool)reponse.Result ? "OK" : "DENIED");
}
else
{
    PackageHost.WriteError("Aucune réponse !");
}</pre><p></p>
<h4>Async/Await</h4>
<p>Aussi vous pouvez utiliser le pattern async/await, très pratique pour les packages UI WPF/Winform :</p>
<p></p><pre class="crayon-plain-tag">public async void Logon()
{
    bool reponse = await PackageHost.CreateMessageProxy("MonPremierPackage").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" });
    PackageHost.WriteInfo(reponse ? "OK" : "DENIED");
}</pre><p></p>
<h4>Résultat de la tache</h4>
<p>Notez bien que le proxy dynamique vous renverra toujours une “Task&lt;<strong>dynamic</strong>&gt;” quelque soit le type générique précisé au niveau de l’appel du MessageCallback (“bool” dans l’exemple du “Logon”).</p>
<p>Cependant le résultat de la tache (<em>Task.Result</em>) est bien du type que celui passé au niveau de l’appel du MessageCallback.</p>
<p>Si vous souhaitez toutefois récupérer une Task&lt;T&gt; où T est le type de retour de votre saga, vous devez créer une nouvelle tache pour réaliser le “cast” à la suite de la tache créée par Constellation.</p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">Task&lt;dynamic&gt; task = PackageHost.CreateMessageProxy("MonPremierPackage").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" });
Task&lt;bool&gt; logonTask = task.ContinueWith&lt;bool&gt;(t =&gt; (bool)t.Result);</pre><p></p>
<h4>Annuler les taches</h4>
<p>Lorsque l’on créé des taches en .NET on peut avoir besoin de leurs associer un jeton d’annulation : le <em>CancellationToken</em>.</p>
<p>Pour cela, il vous suffit de passer un “CancellationToken” comme dernier argument de votre invocation du MessageCallback :</p>
<p></p><pre class="crayon-plain-tag">CancellationTokenSource source = new CancellationTokenSource(1000);
CancellationToken token = source.Token;
try
{
    Task&lt;dynamic&gt; reponse = PackageHost.CreateMessageProxy("ConstellationPackageConsole1").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" }, token);
    PackageHost.WriteInfo("Result = {0}", reponse.Result);
}
catch (AggregateException ae)
{
    foreach (Exception e in ae.InnerExceptions)
    {
        if (e is TaskCanceledException)
            PackageHost.WriteError("Unable to compute mean: {0}", ((TaskCanceledException)e).Message);
        else
            PackageHost.WriteError("Exception: " + e.GetType().Name);
    }
}
finally
{
    source.Dispose();
}</pre><p></p>
<p>Dans l’exemple ci-dessus on crée un <em>CancellationToken</em> à partir d’un <em>CancellationTokenSource</em> que l’on passe en tant que dernier paramètre du MessageCallback.</p>
<p>Le <em>CancellationTokenSource</em> est ici construit pour annuler la tache après 1 seconde (1000 ms). Vous pouvez aussi annuler la tache en en appelant la méthode “Cancel” sur l&rsquo;objet <em>CancellationTokenSource</em> :</p>
<p></p><pre class="crayon-plain-tag">source.Cancel();</pre><p></p>
<p>Bien entendu, le proxy dynamique se sert de votre <em>CancellationToken</em> pour savoir quand annuler la tache. De plus notez bien que le proxy retire ce <em>CancellationToken</em> des paramètres du message (= le <em>CancellationToken</em> n’est pas envoyé dans le message !).</p>
<p>Prenez garde à bien gérer les exceptions, si la tache est annulée une exception “<em>TaskCanceledException</em>” est levée.</p>
<h4>Le contexte du message</h4>
<p>Dans une méthode marquée comme “MessageCallback” ou dans le callback de retour d’une saga (<em>OnSagaResponse</em>) vous pouvez toujours accéder au contexte de réception du message avec la propriété “<em>MessageContext.Current</em>”.</p>
<p>En effet les MessageCallbacks ou les callbacks de retour des sagas sont invoqués dans un thread à part ce qui permet de l’attacher au contexte de réception du message.</p>
<p>Cependant avec les taches, le résultat est dispatché dans le thread de l’appelant. Autrement dit, vous ne pouvez pas accéder au contexte courant (<em>MessageContext.Current</em>) !</p>
<p>La solution consiste à “demander” au proxy dynamique de vous “remplir” un contexte que vous avez initialisé au préalable.</p>
<p>Pour ce faire, commencez par déclarer un contexte vide (<em>MessageContext.None</em>) et passer l’instance comme dernier paramètre d&rsquo;un appel :</p>
<p></p><pre class="crayon-plain-tag">MessageContext context = MessageContext.None;
Task&lt;dynamic&gt; reponse = PackageHost.CreateMessageProxy("ConstellationPackageConsole1").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" }, context);
PackageHost.WriteInfo("Result = {0} - Response received from : {1}", reponse.Result, context.Sender.FriendlyName);</pre><p></p>
<p>Une fois la tache complétée, la variable “context” sera remplie avec le contexte de la réponse lors de la réception. Vous pourrez donc accéder au contexte même dans vos taches.</p>
<p>Le MessageContext est toujours le dernière paramètr et le CancellationToken est donc l’avant dernier paramètre dans le cas où vous utilisez les deux :</p>
<p></p><pre class="crayon-plain-tag">CancellationTokenSource source = new CancellationTokenSource(1000);
CancellationToken token = source.Token;
MessageContext context = MessageContext.None;
try
{
    Task&lt;dynamic&gt; reponse = PackageHost.CreateMessageProxy("ConstellationPackageConsole1").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" }, token, context);
    PackageHost.WriteInfo("Result = {0} - Response received from : {1}", reponse.Result, context.Sender.FriendlyName);
}
catch (AggregateException ae)
{
    foreach (Exception e in ae.InnerExceptions)
    {
        if (e is TaskCanceledException)
            PackageHost.WriteError("Unable to compute mean: {0}", ((TaskCanceledException)e).Message);
        else
            PackageHost.WriteError("Exception: " + e.GetType().Name);
    }
}
finally
{
    source.Dispose();
}</pre><p></p>
<h3>Générateur de code</h3>
<p>Comme l’ensemble des MessageCallbacks sont déclarés dans la Constellation (sauf si ils sont marqués comme “<a href="/client-api/net-package-api/messagecallbacks/#MessageCallback_cache">Hidden</a>”), il est possible de générer du code. Vous pouvez <a href="/constellation-platform/constellation-sdk/generateur-de-code/">lire un article très complet sur le sujet ici</a>.</p>
<p>Dans le menu contextuel de votre projet Visual Studio, sélectionnez “Generate Code” :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-125.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Générer du code" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-102.png" alt="Générer du code" width="424" height="330" border="0" /></a></p>
<p align="left">Sélectionnez votre Constellation et cliquez sur “Discover” :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-126.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Générer du code" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-103.png" alt="Générer du code" width="424" height="469" border="0" /></a></p>
<p align="left">Sélectionnez le ou les packages que vous souhaitez invoquer depuis votre package et cliquez sur “Generate”.</p>
<p align="left">Le générateur de code va créer différentes classes présentant votre Constellation avec les packages sélectionnés (MessageCallbacks et StateObjects).</p>
<p align="left">Dans notre cas nous allons inclure la définition des MessagesCallbacks de notre package “MonPremierPackage”.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-127.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Ajout du using" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-104.png" alt="Ajout du using" width="424" height="132" border="0" /></a></p>
<p align="left">Commençons donc par ajouter le using vers le MessageCallbacks de MonPremierPackage :</p>
<p></p><pre class="crayon-plain-tag">using ConstellationPackageConsole1.MonPremierPackage.MessageCallbacks;</pre><p></p>
<p align="left">Dans la classe générée “MyConstellation” vous retrouverez la liste des sentinelles et packages de votre Constellation :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-128.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Enumération générée" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-105.png" alt="Enumération générée" width="424" height="65" border="0" /></a></p>
<p>Vous pourrez alors créer un scope personnalisé pour le package sélectionné :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-129.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageScope généré par package" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-106.png" alt="MessageScope généré par package" width="424" height="84" border="0" /></a></p>
<p align="left">Ce scope personnalisé contiendra l’ensemble des MessageCallbacks :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-130.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-107.png" alt="image" width="424" height="69" border="0" /></a></p>
<p align="left">Et sur chaque MessageCallback, vous retrouvez les bons types de retour, les commentaires et les types complexes proprement générés :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-131.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageCallbacks générés" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-108.png" alt="MessageCallbacks générés" width="424" height="67" border="0" /></a></p>
<p>De ce fait, pour reprendre l’exemple du MessageCallback “Logon”, on pourra écrire le code :</p>
<p></p><pre class="crayon-plain-tag">var context = MessageContext.None;
var token = new CancellationTokenSource(5000).Token;
var user = new UserInfo() { User = "seb", Password = "seb" };

var task = MyConstellation.Packages.MonPremierPackage.CreateMonPremierPackageScope().Logon(user, token, out context);

PackageHost.WriteInfo("Logon user {0} - Result = {1} - Sender : {2}", user.User, task.Result, context.Sender.FriendlyName);</pre><p></p>
<p><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-132.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; display: block; padding-right: 0px; margin-right: auto; border-width: 0px;" title="Démonstration" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-109.png" alt="Démonstration" width="424" height="205" border="0" /></a></p>
<p>N’hésitez pas <a href="/constellation-platform/constellation-sdk/generateur-de-code/">lire cet article très complet sur la génération de code C#</a> dans Constellation.</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/">Envoyer des messages &#038; Invoquer des MessageCallbacks</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Mise en cache de page à l’aide de Disk: Enhanced 

Served from: developer.myconstellation.io @ 2026-01-23 02:50:13 by W3 Total Cache
-->