﻿<?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 MessageScope - Constellation</title>
	<atom:link href="https://developer.myconstellation.io/tag/messagescope/feed/" rel="self" type="application/rss+xml" />
	<link>https://developer.myconstellation.io/tag/messagescope/</link>
	<description>Votre plateforme d&#039;interconnexion</description>
	<lastBuildDate>Thu, 19 Apr 2018 07:55:10 +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 MessageScope - Constellation</title>
	<link>https://developer.myconstellation.io/tag/messagescope/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Envoyer des messages et invoquer des MessageCallbacks en Python</title>
		<link>https://developer.myconstellation.io/client-api/python-api/envoyer-des-messages-et-invoquer-des-messagecallbacks-en-python/</link>
					<comments>https://developer.myconstellation.io/client-api/python-api/envoyer-des-messages-et-invoquer-des-messagecallbacks-en-python/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Wed, 24 Aug 2016 09:47:10 +0000</pubDate>
				<category><![CDATA[Python API]]></category>
		<category><![CDATA[Message]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<category><![CDATA[MessageScope]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[SendMessage]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2509</guid>

					<description><![CDATA[<p>Envoyer un message Pour envoyer un message et donc invoquer un MessageCallback depuis un package Python vous devez utiliser la méthode “Constellation.SendMessage”. Par exemple : [crayon-6970eee9b4db3305786782/] Ici par exemple on envoi un message au package “SMS” pour invoquer le MessageCallback</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/python-api/envoyer-des-messages-et-invoquer-des-messagecallbacks-en-python/">Envoyer des messages et invoquer des MessageCallbacks en Python</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h3>Envoyer un message</h3>
<p>Pour envoyer un message et donc <a href="/concepts/messaging-message-scope-messagecallback-saga/">invoquer un MessageCallback</a> depuis un package Python vous devez utiliser la méthode “<em>Constellation.SendMessage</em>”. Par exemple :</p>
<p></p><pre class="crayon-plain-tag">Constellation.SendMessage("SMS", "SendMessage", [ "+33676903634", "Bonjour Constellation" ])</pre><p></p>
<p>Ici par exemple on envoi un message au package “SMS” pour invoquer le MessageCallback “SendMessage” en passant en argument deux paramètres de type string.</p>
<p>Le MessageCallbacks Explorer de la Console Constellation permet de lister l’ensemble des MC déclarés par les packages de votre Constellation.</p>
<p>Par exemple, avec le package <a href="/package-library/nest/">Nest</a> déployé dans votre Constellation, on retrouvera un MessageCallback  “SetTargetTemperature” pour piloter la température de consigne d’un thermostat Nest.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-21.png"><img class="colorbox-2509"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-20.png" alt="image" width="350" height="99" border="0" /></a></p>
<p>Pour l’invoquer depuis notre code Python :</p>
<p></p><pre class="crayon-plain-tag">Constellation.SendMessage("Nest", "SetTargetTemperature", [ "thermostatId", 19 ], Constellation.MessageScope.package)</pre><p></p>
<p>On peut également passer en paramètre un objet complexe. Par exemple le MC “AreaArm” du package Paradox permet d’armer le système d’alarme en passant en paramètre un objet “ArmingRequestData” contenant le secteur à armer, le mode d’armement et le PIN.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-22.png"><img class="colorbox-2509"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-21.png" alt="image" width="350" height="121" border="0" /></a></p>
<p>Le code Python pour invoquer ce MC sera alors :</p>
<p></p><pre class="crayon-plain-tag">Constellation.SendMessage("Paradox", "AreaArm", { "Area":"All", "Mode":1, "PinCode":"0000" }, Constellation.MessageScope.package)</pre><p></p>
<p>Vous pouvez également passer plusieurs arguments à votre MC en combinant type simple et type complexe. Par exemple le MC “ShowNotification” du package <a href="/package-library/xbmc/">Xbmc</a> permettant d’afficher une notification sur une interface Kodi/XBMC prend deux paramètres : le nom d l’hôte XBMC (un type simple) et le détail de la notification à afficher (un type complexe) :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-23.png"><img class="colorbox-2509"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-22.png" alt="image" width="350" height="143" border="0" /></a></p>
<p></p><pre class="crayon-plain-tag">Constellation.SendMessage("Xbmc", "ShowNotification", [ xbmcName, { "Title":"Hello Constellation", "Message":"Hello I'm Python" } ], Constellation.MessageScope.package)</pre><p></p>
<p>Les exemples de message ci-dessus sont tous envoyés à un package mais vous pouvez également envoyer vos messages à <a href="/concepts/messaging-message-scope-messagecallback-saga/">différents scopes</a>.</p>
<p>Par exemple pour envoyer le message “Demo” sans aucun paramètre au groupe A, on écrira :</p>
<p></p><pre class="crayon-plain-tag">Constellation.SendMessage("A", "Demo", {}, Constellation.MessageScope.group)</pre><p></p>
<p>Les scopes disponibles sont :</p>
<ul>
<li>group</li>
<li>package</li>
<li>sentinel</li>
<li>others</li>
<li>all</li>
</ul>
<p>Notez par ailleurs que le paramètre “MessageScope” de la méthode “SendMessage” est optionnel. Si il n’est pas spécifié le scope par défaut est “package”.</p>
<h3>Envoyer des messages avec réponse : les Sagas</h3>
<p>Si le MC que vous invoquez retourne un message de réponse, vous devez envoyer votre message dans une saga. Pour cela vous pouvez utiliser la méthode “SendMessageWithSaga” dans laquelle vous devrez spécifier la fonction qui sera invoquée lors de la réception de la réponse.</p>
<p>Par exemple reprenons le MessageCallback “AreaArm” du package Paradox :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-24.png"><img class="colorbox-2509"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-23.png" alt="image" width="350" height="121" border="0" /></a></p>
<p align="left">Comme vous le constatez, ce MessageCallback retourne un “Boolean” pour indiquer si l’armement a bien été déclenché.</p>
<p align="left">On peut donc invoquer ce MC dans une saga et attacher un callback de réponse pour afficher dans le logs de notre package si l’armement a réussi :</p>
<p></p><pre class="crayon-plain-tag">Constellation.SendMessageWithSaga(lambda response:
   Constellation.WriteInfo("Arm result is %s" % response),
"Paradox", "AreaArm", { "Area":"All", "Mode":1, "PinCode":"0000" })</pre><p></p>
<p>Ici nous avons utilisé une fonction lambda pour simplifier la lecture mais vous pouvez également définir une fonction classique dans votre code.</p>
<p>Le paramètre “response” utilisé dans la fonction callback est l’objet de la réponse envoyé par le package qui a reçu votre message. Ici “response” est un “Boolean” car le MC “AreaArm” retourne un booléen mais il peut être de n’importe quel type (simple ou complexe).</p>
<p>Le MessageCallback Explorer de la Console Constellation vous donnera tous les détails.</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/python-api/envoyer-des-messages-et-invoquer-des-messagecallbacks-en-python/">Envoyer des messages et invoquer des MessageCallbacks en 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/envoyer-des-messages-et-invoquer-des-messagecallbacks-en-python/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Messaging : Message, Scope, MessageCallback et Saga</title>
		<link>https://developer.myconstellation.io/concepts/messaging-message-scope-messagecallback-saga/</link>
					<comments>https://developer.myconstellation.io/concepts/messaging-message-scope-messagecallback-saga/#comments</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Wed, 16 Mar 2016 14:40:29 +0000</pubDate>
				<category><![CDATA[Concepts]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[Messaging]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<category><![CDATA[MessageScope]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=1349</guid>

					<description><![CDATA[<p>Tous systèmes connectés dans Constellation (les packages réels ou virtuels et les consommateurs) peuvent tous envoyer ou recevoir des messages (sauf si des autorisations restreignent cela). Message &#38; Scope Les notions de base du Messaging de Constellation sont : Un message</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/concepts/messaging-message-scope-messagecallback-saga/">Messaging : Message, Scope, MessageCallback et Saga</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Tous systèmes connectés dans Constellation (les packages réels ou virtuels et les consommateurs) peuvent tous envoyer ou recevoir des messages (sauf si des autorisations restreignent cela).</p>
<h3>Message &amp; Scope</h3>
<p>Les notions de base du Messaging de Constellation sont :</p>
<p>Un message :</p>
<ul>
<li>porte obligatoirement une clé (le MessageKey), en quelque sorte l’équivalent du “Sujet” d’un mail.</li>
<li>peut contenir optionnellement un contenu, nommé “Data”</li>
<li>est envoyé à un scope.</li>
</ul>
<p>Un scope :</p>
<ul>
<li>défini les destinataires d’un message</li>
<li>peut être de différents types :
<ul>
<li>All : c’est à dire que tous les systèmes connectés dans Constellation recevront le message (y compris l’émetteur)</li>
<li>Other : tout le monde sauf l’émetteur</li>
<li>Package : cible un ou plusieurs packages</li>
<li>Sentinel : cible tous les packages hébergés sur les sentinelles visées par le scope</li>
<li>Group : cible les packages ou consommateurs appartenant aux groupes visés par le scope</li>
</ul>
</li>
</ul>
<p>Les scopes “Package”, “Sentinel” et “Group” peuvent déclarer une liste de packages, de sentinelles et de groupes.</p>
<ul>
<li>Lorsque l’on cible une sentinelle, on vise tous les packages qu’elle héberge.</li>
<li>Lorsque l’on cible un package, on vise toutes les instances de ce package sur les sentinelles de votre Constellation.</li>
</ul>
<p>Si vous voulez cibler un seul package en particulier, vous devez obligatoirement créer un scope de type Package et définir le nom du package <strong>préfixé</strong> du nom de la sentinelle avec la nomenclature “SENTINEL/Package”.</p>
<p>Chaque package ou consommateur peut s’inscrire à un groupe ou être inscrit d’office dans la configuration du serveur (lire <a href="/constellation-platform/constellation-server/fichier-de-configuration/">l’article sur les groupes</a>).</p>
<h3>MessageCallback</h3>
<p>Les messages dans Constellation servent essentiellement à invoquer des méthodes. On appelle cela des “MessageCallbacks” le fait de lier un message à une fonction de votre programme.</p>
<p>Il s’agit tout simplement déclarer une méthode de votre code comme « MessageCallback », c’est à dire que si le package reçoit un message dont la clé du message est le nom d’une méthode déclarée comme MessageCallback, alors cette méthode sera invoquée. Le contenu du message reçu (c’est à dire les “Datas”)  contiendra les paramètres de la méthode.</p>
<p>De la même façon, pour invoquer une méthode d’un autre package, il suffit d’envoyer un message dont la clé est la méthode à invoquer avec comme contenu de message les paramètres à passer à cette méthode.</p>
<h3>Les Sagas</h3>
<p>Chaque message envoyé dans Constellation est à sens unique. Il n’y a aucun retour.</p>
<p>Un message est envoyé à un scope,  il peut ne jamais être reçu (si « personne » n’est visée par le scope) ou à l’inverse être reçu par tout le monde.</p>
<p>Cependant il y a certain cas où il est indispensable d’obtenir une réponse à un message ! Comme en programmation, il n’y a pas que des procédures, il y a aussi des fonctions.</p>
<p>Pour cela, Constellation propose le concept de “Saga”. Une saga est un identifiant porté par un scope. Pour faire l’analogie, “<em>La guerre des étoiles</em>”, “<em>L&rsquo;Empire contre-attaque</em> » ou “<em>Le Retour du Jedi</em>” sont trois films distincts qui portent le même identifiant de Saga : “Star Wars”.</p>
<p>Il en va de même pour les messages Constellation. Pour “répondre”, il suffit d’envoyer un message “de réponse” à un scope qui vise l’émetteur du message original en prenant soin d’utiliser le même identifiant de saga.</p>
<p>Ainsi l’émetteur en recevant ce message, pourra savoir qu’il s’agit de la réponse à son message car il retrouvera le même identifiant de saga.</p>
<p>Bien entendu l’identifiant de Saga doit être unique et aléatoire pour chaque couple “Request / Response” .</p>
<p>De ce fait, lorsque l’on reçoit un message, si le scope porte un identifiant de Saga cela veut dire que l’émetteur a envoyé le message “dans une Saga”, il s’attend donc à recevoir une réponse. Le clé d’un message de réponse est toujours “__Response”.</p>
<h3>Auto-description des MessageCallbacks</h3>
<p>Chaque packages (virtuel ou non) doit ou devrait déclarer son “Package Descriptor”.</p>
<p>Il s’agit de la description du package qui contient entre autre les MessageCallbacks du package, c’est à dire les méthodes que le package expose dans la Constellation.</p>
<p>Le <a href="/constellation-platform/constellation-console/messagecallbacks-explorer/">MessageCallback Explorer</a> de la Console Constellation exploite les “Package Descriptors” connus pour créer la liste de l&rsquo;ensemble des MessageCallbacks exposés par les package d&rsquo;une Constellation avec le détail des paramètres en entrée et le type de retour. Il est également possible d&rsquo;invoquer ces MC avec une interface de test et de générer le code pour invoquer ces MC sur les différentes API de Constellation.</p>
<p><a href="https://developer.myconstellation.io/wp-content/uploads/2017/05/image-59.png"><img loading="lazy" class="wp-image-4600 aligncenter colorbox-1349" title="MessageCallbacks Explorer" src="https://developer.myconstellation.io/wp-content/uploads/2017/05/image-59-300x91.png" alt="MessageCallbacks Explorer" width="323" height="98" srcset="https://developer.myconstellation.io/wp-content/uploads/2017/05/image-59-300x91.png 300w, https://developer.myconstellation.io/wp-content/uploads/2017/05/image-59.png 605w" sizes="(max-width: 323px) 100vw, 323px" /></a></p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/concepts/messaging-message-scope-messagecallback-saga/">Messaging : Message, Scope, MessageCallback et Saga</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/concepts/messaging-message-scope-messagecallback-saga/feed/</wfw:commentRss>
			<slash:comments>1</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[MessageScope]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[Messaging]]></category>
		<category><![CDATA[MessageContext]]></category>
		<category><![CDATA[Proxy]]></category>
		<category><![CDATA[SendMessageProxy]]></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-21 16:21:13 by W3 Total Cache
-->