﻿<?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 Proxy - Constellation</title>
	<atom:link href="https://developer.myconstellation.io/tag/proxy/feed/" rel="self" type="application/rss+xml" />
	<link>https://developer.myconstellation.io/tag/proxy/</link>
	<description>Votre plateforme d&#039;interconnexion</description>
	<lastBuildDate>Wed, 28 Aug 2019 14:46:13 +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 Proxy - Constellation</title>
	<link>https://developer.myconstellation.io/tag/proxy/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Exposer Constellation en HTTPS derrière un reverse proxy avec Nginx et Let&#8217;s Encrypt</title>
		<link>https://developer.myconstellation.io/constellation-platform/constellation-server/exposer-constellation-en-https-derriere-un-reverse-proxy-avec-nginx-et-lets-encrypt/</link>
					<comments>https://developer.myconstellation.io/constellation-platform/constellation-server/exposer-constellation-en-https-derriere-un-reverse-proxy-avec-nginx-et-lets-encrypt/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Wed, 25 Apr 2018 08:11:01 +0000</pubDate>
				<category><![CDATA[Constellation Server]]></category>
		<category><![CDATA[Certificat]]></category>
		<category><![CDATA[TCP]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[HTTPS]]></category>
		<category><![CDATA[Routeur]]></category>
		<category><![CDATA[Configuration]]></category>
		<category><![CDATA[IT]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[SSL]]></category>
		<category><![CDATA[Constellation]]></category>
		<category><![CDATA[Proxy]]></category>
		<category><![CDATA[Reverse Proxy]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=5890</guid>

					<description><![CDATA[<p>Pour sécuriser votre Constellation vous devez utilise le protocole HTTPS afin de chiffrer toutes les communications en SSL. Si vous avez un serveur Windows, vous pouvez également utiliser IIS pour configurer un reverse proxy vers Constellation. Dans cet article nous</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/constellation-platform/constellation-server/exposer-constellation-en-https-derriere-un-reverse-proxy-avec-nginx-et-lets-encrypt/">Exposer Constellation en HTTPS derrière un reverse proxy avec Nginx et Let&rsquo;s Encrypt</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Pour sécuriser votre Constellation vous devez utilise le protocole HTTPS afin de chiffrer toutes les communications en SSL.</p>
<p><img loading="lazy" class="alignnone size-full wp-image-3796 aligncenter colorbox-5890" src="https://developer.myconstellation.io/wp-content/uploads/2016/08/ssl.jpg" alt="" width="253" height="189" /></p>
<p>Si vous avez un serveur Windows, vous pouvez également <a href="/constellation-platform/constellation-server/exposer-constellation-derrire-un-serveur-web-reverse-proxy/">utiliser IIS pour configurer un reverse proxy</a> vers Constellation.</p>
<p>Dans cet article nous allons découvrir comment exposer le serveur Constellation derrière un serveur Nginx protégé avec un certificat SSL Let’s Encrypt.</p>
<h3>Prérequis : avoir une Constellation exposée publiquement avec un nom DNS</h3>
<p>Avant de démarrer vous devez avoir un serveur Constellation opérationel.</p>
<p>Si vous installez Constellation sur un Linux, cela se résume à lancer la commande ci-dessous et à suivre l&rsquo;assistant :</p>
<p></p><pre class="crayon-plain-tag">wget -O install.sh https://developer.myconstellation.io/download/installers/install-linux.sh &amp;&amp; chmod +x install.sh &amp;&amp; ./install.sh</pre><p></p>
<p>Pour plus d’information, veuillez suivre le guide : <a href="/constellation-platform/constellation-server/installer-constellation-sur-linux/">Installer Constellation sur Linux.</a></p>
<p>On considéra à ce stade que votre serveur Constellation est démarré et opérationnel. Vous pouvez lancer la commande suivante pour vérifier le statut des services Constellation :</p>
<p></p><pre class="crayon-plain-tag">sudo supervisorctl status</pre><p></p>
<p>Vous devriez voir le “<em>constellation-server</em>” avec le statut “RUNNING” (et la sentinelle si déployée) :</p>
<p></p><pre class="crayon-plain-tag">sebastien@ubuntu:~$ sudo supervisorctl status
constellation-sentinel           RUNNING   pid 1194, uptime 1 day, 17:36:48
constellation-server             RUNNING   pid 2888, uptime 1 day, 15:06:41</pre><p></p>
<p>Vous pouvez également installer Constellation sur un système Windows (voir <a href="/getting-started/installer-constellation/">le guide</a>).</p>
<p>En effet, le reverse proxy (ici Ngnix) qui sera installé sur un système Linux peut exposer un service tel que Constellation quelque soit le serveur sur lequel il est déployé. Le reverse proxy n&rsquo;est pas nécessairement sur la même machine sur le ou les services à exposer.</p>
<p>Il est donc possible d&rsquo;installer un serveur Linux avec Nginx pour exposer en SSL un serveur Constellation sur un système Windows de la même manière que nous pouvons installer un serveur <a href="/constellation-platform/constellation-server/exposer-constellation-derrire-un-serveur-web-reverse-proxy/">Windows avec IIS</a> pour exposer en SSL un serveur Constellation sur un système Linux !</p>
<p>Dans ce guide nous avons installer le serveur Constellation et le reverse proxy Nginx sur le même serveur, sous Linux Ubuntu 16.</p>
<p>Si vous souhaitez activer le HTTPS et donc ajouter un certificat SSL, vous devez nécessairement avoir un nom DNS qui pointe vers l’adresse IP (public) de votre serveur de reverse proxy.</p>
<p>Plusieurs options s&rsquo;offre à vous :</p>
<ul>
<li>Si vous avez un nom de domaine, modifiez votre zone DNS pour ajouter un “host” (enregistrement A ou AAAA) vers l’adresse IP (public) de votre Constellation.</li>
<li>SI vous n’avez pas de nom de domaine :
<ul>
<li>Achetez-en un ! Comptez environ 15€/an pour les extensions standards (.fr, .net, .com), 2,99€ HT par an pour  un <a href="https://www.ovh.com/fr/domaines/" target="_blank" rel="noopener noreferrer">.ovh</a></li>
<li>Utilisez un service de “Dynamic DNS” comme dyndns.fr, dyn.com ou autre</li>
<li>Certains FAI comme Free proposent d&rsquo;attacher un nom DNS type xxxx.hd.free.fr à votre IP de connexion</li>
<li>Certains NAS comme Synology permettent aussi de créer un DDNS type xxx.synology.me vers votre IP de connexion</li>
</ul>
</li>
</ul>
<p>Dans le cas présent, j’ai crée l’entrée DNS “demo.internal.myconstellation.io” qui pointe vers l’adresse IP public du serveur Constellation installé sur un Ubuntu (le DNS doit pointer votre le serveur où sera installé le reverse proxy dans la mesure où tout passera par lui. Etant donné que le reverse proxy sera sur le même serveur que le service Constellation on peut dire que le DNS pointe vers le serveur Constellation).</p>
<p>Bien évidement, si votre serveur est installé dernière un routeur avec du NAT (typiquement sur un réseau local derrière une box Internet) vous devez configurer la redirection de port sur votre routeur/box internet.</p>
<p>Encore une fois, on part du principe que le serveur de R.P et Constellation sont sur le même serveur, donc la même IP interne.</p>
<p>Dans un premier temps redirigez seulement le port 8088 en tcp sur l’IP interne de votre serveur Constellation. A noter que nous supprimerons cette redirection une fois le reverse proxy installé.</p>
<p>Donc pour résumer et avant de démarrer, vous devez avoir votre serveur Constellation démarré répondant sur l’URL : <a href="http://&lt;mon_nom_dns&gt;:8088">http://&lt;mon_nom_dns&gt;:8088</a></p>
<p>Dans mon cas : <a href="http://demo.internal.myconstellation.io:8088">http://demo.internal.myconstellation.io:8088</a> :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-1.png"><img class="colorbox-5890"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="Serveur Constellation sur un nom DNS" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb.png" alt="Serveur Constellation sur un nom DNS" width="484" height="291" border="0" /></a></p>
<p>Voilà vous êtes prêt, votre Constellation est démarrée et elle répond bien sur un nom DNS public depuis l&rsquo;internet.</p>
<h3>Exposer Constellation derrière Nginx</h3>
<p>Avant de démarrer il est recommandé de mettre à jour le référentiel du gestionnaire de package par la commande suivante :</p>
<p></p><pre class="crayon-plain-tag">sudo apt-get update</pre><p></p>
<p>Ensuite installez le serveur Web Nginx avec la commande :</p>
<p></p><pre class="crayon-plain-tag">sudo apt-get install nginx</pre><p></p>
<p>Les fichiers de configuration sont situés dans le répertoire “<em>/etc/nginx/sites-available/</em>” et pour les activer on crée un lien symbolique vers ces fichiers dans le répertoire “<em>/etc/nginx/sites-enabled</em>”.</p>
<p>Pour commencer désactivez la configuration par défaut par la commande ci-dessous :</p>
<p></p><pre class="crayon-plain-tag">sudo rm /etc/nginx/sites-enabled/default</pre><p></p>
<p>Comme vous l’aurez compris le contenu de cette configuration par défaut est toujours présente dans le répertoire “<em>/etc/nginx/sites-available/</em>” mais non activée car on a supprimé le lien symbolique vers ce fichier dans le répertoire “<em>site-enabled</em>”.</p>
<p>Maintenant nous allons créer une configuration pour notre reverse proxy avec la commande :</p>
<p></p><pre class="crayon-plain-tag">sudo nano /etc/nginx/sites-available/constellation</pre><p></p>
<p>Dans ce fichier, copiez le contenu suivant :</p>
<p></p><pre class="crayon-plain-tag">server {
    listen 80; listen [::]:80;
    server_name demo.internal.myconstellation.io;

    location / {
        proxy_pass http://localhost:8088;

        set $content_length_safe $http_content_length;
        if ($content_length_safe = "") {
            set $content_length_safe 0;
        }
        proxy_set_header Content-Length $content_length_safe;

        proxy_set_header Host $host;
        proxy_set_header Connection "";
        proxy_http_version 1.1;

        proxy_buffering off;
        proxy_cache off;
        proxy_connect_timeout 30;
        proxy_send_timeout 30;
        proxy_read_timeout 150;
    }
}</pre><p></p>
<p>Vous devez modifier le paramètre “<em>server_name</em>” avec le nom DNS de votre serveur Constellation, dans le cas présent “demo.internal.myconstellation.io”.</p>
<p>Il est important de bien reprendre les mêmes options, notamment le “<em>proxy_buffering</em>” pour permettre les “<em>server-Sent events</em>” vers le serveur Constellation.</p>
<p>Dans le cas présent Nginx va « proxifer » les requêtes vers <em>http://localhost:8088</em>, c&rsquo;est à dire au service Constellation (port 8088) installé sur le même serveur (localhost).</p>
<p>Tapez ensuite sur la combinaison de touches “Ctrl+X” pour quitter en prenant suivant d’enregistrer le fichier. Puis, pour activer cette configuration, créez le lien symbolique suivant :</p>
<p></p><pre class="crayon-plain-tag">sudo ln -s /etc/nginx/sites-available/constellation  /etc/nginx/sites-enabled/constellation</pre><p></p>
<p>Avant de redémarrer Nginx, éditez le fichier de configuration global pour augmenter la taille maximale des requêtes entrantes afin de pouvoir uploader des packages Constellation sur le serveur (par défaut cette taille est fixée à 1Mo, autrement dit vous obtiendrez une erreur 413 « Request Entity Too Large » si vous tentez d&rsquo;uploader un package de plus de 1Mo).</p>
<p></p><pre class="crayon-plain-tag">sudo nano /etc/nginx/nginx.conf</pre><p></p>
<p>Sous la section « http », ajoutez l&rsquo;option « <strong>client_max_body_size</strong> » (ou si l&rsquo;option existe déjà, modifiez sa valeur) que nous fixerons à 100 Méga :</p>
<p></p><pre class="crayon-plain-tag">client_max_body_size 100M;</pre><p></p>
<p>Pour finir, rechargez Nginx afin prendre en compte notre nouvelle configuration :</p>
<p></p><pre class="crayon-plain-tag">sudo systemctl reload nginx</pre><p></p>
<p>Votre Constellation est maintenant accessible derrière Nginx sur le port 80.</p>
<p>Rendez-vous donc sur l’adresse http://&lt;votre_nom_dns&gt; (sans spécifier le port, car 80 par défaut) pour vérifier que le reverse proxy est opérationnel. Dans le cas présent <a href="http://demo.internal.myconstellation.io">http://demo.internal.myconstellation.io</a></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-2.png"><img class="colorbox-5890"  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/2018/04/image_thumb-1.png" alt="image" width="484" height="290" border="0" /></a></p>
<p align="left">Ce n’est donc plus Constellation qui répond mais notre serveur Nginx qui lui même communique avec le serveur Constellation local.</p>
<p align="left">Donc pour résumer, sur le port 80 c&rsquo;est le serveur Nginx qui répond en transférant au serveur Constellation sur le port 8088.</p>
<p><span style="text-decoration: underline;">Note</span> : si vous êtes dernière un routeur avec du NAT, n’oubliez pas d’ajouter la redirection du port 80 vers votre serveur Constellation interne. Par la même occasion vous pouvez supprimer la redirection du port 8088, ainsi tout passera nécessairement par Nginx.</p>
<h3>Activer le HTTPS avec des certificats SSL Let’s Encrypt</h3>
<p>Maintenant que votre service Constellation est exposé dernière le serveur Nginx vous allez pouvoir configurer différentes choses sur Nginx comme par exemple des restrictions d&rsquo;accès , l’authentification, des limites (throttling) et bien d’autre chose. Dans le cas présent on va s’intéresser au support du SSL.</p>
<p>Pour activer le HTTPS, il vous faut un certificat SSL. Pour simplifier la démarche, Let’s Encrypt est une autorité de certification lancée en 2015 qui permet d’automatiser la génération de certificat. De plus le service est gratuit ! Les certificats sont valides trois mois, il faudra donc régulièrement les renouveler mais vous allez voir que cette action est entièrement automatisable.</p>
<p>Ici nous allons utiliser <a href="https://certbot.eff.org/" target="_blank" rel="noopener noreferrer">Certbot</a>, un agent installé sur le serveur qui permet de générer et renouveler automatiquement les certificats SSL Let’s Encrypt.</p>
<p>Commencez par ajouter le repository suivant :</p>
<p></p><pre class="crayon-plain-tag">sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update</pre><p></p>
<p>Ensuite installez Certbot pour Nginx :</p>
<p></p><pre class="crayon-plain-tag">sudo apt-get install python-certbot-nginx</pre><p></p>
<p>Une fois installé, lancez la commande “<em>certbot –nginx</em>” en spécifiant le nom DNS vers votre serveur. Dans le cas présent :</p>
<p></p><pre class="crayon-plain-tag">sudo certbot --nginx -d demo.internal.myconstellation.io</pre><p></p>
<p>L’assistant vous demandera tout d’abord votre adresse mail :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-3.png"><img class="colorbox-5890"  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/2018/04/image_thumb-2.png" alt="image" width="484" height="100" border="0" /></a></p>
<p>Après avoir accepté les conditions du service, l’assistant va automatiquement valider un challenge en interrogeant votre site Web (d’où la nécessité d’avoir exposé correctement votre serveur sur Internet avec le nom DNS spécifié), créer le certificat SSL et l&rsquo;ajouter dans votre configuration Nginx.</p>
<p>Pour finir l’assistant vous proposera de modifier automatiquement la configuration de votre Nginx pour rediriger tous les appels HTTP (port 80) vers HTTPS (port 443).</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-4.png"><img class="colorbox-5890"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="Activation de la redirection HTTPS" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-3.png" alt="Activation de la redirection HTTPS" width="484" height="438" border="0" /></a></p>
<p>Choisissiez l’option 2 pour activer cette redirection.</p>
<p>Et voilà, votre serveur Nginx est configuré avec le certificat SSL généré par Let’s Encrypt et toutes les requêtes seront redirigés en HTTPS et donc chiffrés !</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-5.png"><img class="colorbox-5890"  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/2018/04/image_thumb-4.png" alt="image" width="484" height="108" border="0" /></a></p>
<p align="left"><strong>Votre Constellation est maintenant protégée !</strong></p>
<p align="left">Rechargez la page dans votre navigateur (F5) sur l’URL <em>http://&lt;mon_nom_dns&gt;</em> vous constaterez la redirection automatique en <em>https://</em> et le cadenas vert vous informant du chiffrement SSL :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-6.png"><img class="colorbox-5890"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="Constellation en HTTPS" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-5.png" alt="Constellation en HTTPS" width="484" height="290" border="0" /></a></p>
<p align="left">(Note : pour les personnes derrières un NAT, n’oubliez pas non plus d&rsquo;ajouter la redirection du port 443 vers votre serveur Nginx interne)</p>
<p align="left">Pour vérifier le bon renouvellement du certificat vous pouvez utiliser la commande suivante :</p>
<p></p><pre class="crayon-plain-tag">sudo certbot renew --dry-run</pre><p></p>
<p align="left">Certbot a automatiquement installé un trigger dans systemd (ou crontab selon le système) pour réaliser le renouvellement et déploiement automatique de vos certificats avant leurs expirations.</p>
<p align="left">Pour les plus curieux, vous pouvez jeter un œil dans le fichier “<em>/etc/nginx/sites-available/constellation</em>” pour voir les modifications apportées par Certbot.</p>
<h3>Pour aller plus loin</h3>
<h4>Sécuriser le serveur avec un firewall UFW et fail2ban</h4>
<h5>Installer fail2ban</h5>
<p><a href="http://fail2ban.sourceforge.net/">Fail2ban</a> est un script tournant en tâche de fond qui va vérifier si les tentatives d&rsquo;authentification SSH et Nginx; et en cas d&rsquo;attaque, bannir l&rsquo;IP grâce à <code>iptables</code>.</p>
<p></p><pre class="crayon-plain-tag">sudo apt-get install fail2ban</pre><p></p>
<p>Pour plus d’info:  <a title="https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04" href="https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04">https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04</a></p>
<h5>Installer UFW</h5>
<p>UFW est un firewall applicatif. Pour l’installer :</p>
<p></p><pre class="crayon-plain-tag">sudo apt-get install ufw</pre><p></p>
<p>Autorisez ensuite les services HTTP (nécessaire pour le challenge Let’s Encrypt), HTTPS (notre reverse proxy Nginx vers Constellation) et SSH :</p>
<p></p><pre class="crayon-plain-tag">sudo ufw allow http
sudo ufw allow https
sudo ufw allow ssh</pre><p></p>
<p>Pour l’activer :</p>
<p></p><pre class="crayon-plain-tag">sudo ufw enable</pre><p></p>
<p>Votre serveur Linux ne répondra plus que sur les ports 22 (ssh), 80 (http), 443 (https) en IPv4 et IPv6.</p>
<p></p><pre class="crayon-plain-tag">sebastien@ubuntu:~$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
80                         ALLOW       Anywhere
443                        ALLOW       Anywhere
22                         ALLOW       Anywhere
80 (v6)                    ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)
22 (v6)                    ALLOW       Anywhere (v6)</pre><p></p>
<p>Vous noterez que le port 8088 n&rsquo;est maintenant plus accessible car bloqué par le firewall UFW. Il faudra forcement se connecter à Constellation via Nginx en HTTPS. N’oubliez pas alors de modifier l’URI de votre Constellation sur vos sentinelles existantes pour prendre en compte ce changement.</p>
<h4>Ajouter d’autre application Web dernière votre reverse proxy SSL</h4>
<p>Jusqu&rsquo;au présent vous avez configuré un nom DNS type “demo.internal.myconstellation.io” qui pointe vers votre serveur Linux sur lequel le service Nginx répond en HTTP (80) et HTTPS (443) avec un certificat Let’s Encrypt pour “proxifier” les requêtes vers le service Constellation accessible localement sur le port 8088.</p>
<p>Vos utilisateurs se connectent donc forcement en HTTPS sur le reverse proxy pour accéder à Constellation !</p>
<p>La règle configurée dans Ngnix “proxifie” toutes les requêtes à partir de la racine « / » vers Constellation :</p>
<p></p><pre class="crayon-plain-tag">location / {
        proxy_pass http://localhost:8088;
....
}</pre><p></p>
<p>Mais il est également possible d’adapter cette règle pour que votre reverse proxy ne soit plus exclusivement un passe-plat pour Constellation mais aussi pour vos autres services internes (une box domotique, un serveur Web, un objet connecté, une camera IP, etc…).</p>
<p>Vous aurez ainsi la possibilité d’exposer différents services Web internes dernière votre reverse proxy profitant d’un même port TCP (le 443) et donc d’un même canal de communication sécurisé (par le cryptage SSL).</p>
<p>Parmi les différentes options pour ce type de configuration :</p>
<ol>
<li>Reverse proxy en fonction du “server_name”</li>
<li>Reverse proxy en fonction de la “location”</li>
</ol>
<h5>Reverse Proxy en fonction du server_name</h5>
<p>Le principe est de rejouer ce tutoriel depuis le début pour chacune de vos applications à exposer.</p>
<p>Vous devrez ainsi créer une adresse DNS vers votre IP public pour chaque site, créer une configuration Nginx en changeant le « <em>server_name</em> » et « <em>proxy_pass</em> » vers la ressource interne à exposer et créer un certificat SSL avec Certbot pour tous vos sites créés.</p>
<p>Vous aurez ainsi une multitude de nom DNS qui pointerons tous vers votre serveur Nginx qui lui redirigera vers les ressources internes en fonction du « server_name ». Par exemple “constellation.mondomaine.fr”, “macamera.mondomaine.fr”, “jeedom.mondomaine.fr”, etc.. etc..</p>
<p>La configuration est simple car il s’agit de répéter ce tutoriel pour chaque service, par contre l’administration est un peu lourde et vous aurez autant de sous domaine et donc de certificat que de service à exposer.</p>
<h5>Reverse Proxy en fonction de la “location”</h5>
<p>Dans ce mode, nous gardons un seul site Nginx (celui configuré dans le fichier <em>/etc/nginx/sites-available/constellation</em>) et donc un seul nom de domaine (ici <em>demo.internal.myconstellation.io</em>) avec son certificat associé.</p>
<p>Cependant au lieu de “rediriger” les requêtes depuis la racine « / » vers Constellation nous allons créer plusieurs “location”.</p>
<p>Prenons un exemple pour bien comprendre. Ici le serveur Ngnix est installé sur la même que le serveur Constellation, donc localhost. Imaginons que dans ce même réseau LAN, j’ai par exemple un serveur ZoneMinder qui répond sur 192.168.0.10 et une box Jeedom sur 192.168.0.11.</p>
<p>Je pourrais éditer la configuration Nginx de cette façon :</p>
<p></p><pre class="crayon-plain-tag">location /constellation/ {
        proxy_pass http://localhost:8088/constellation/;

        proxy_set_header Host $host;
        proxy_set_header Connection "";
        proxy_http_version 1.1;

        proxy_buffering off;
        proxy_cache off;
        proxy_connect_timeout 30;
        proxy_send_timeout 30;
    }
    
    
location /zm/ {
        proxy_pass <a href="http://192.168.0.10/zm/;">http://192.168.0.10/zm/;

</a>        proxy_set_header Host $host;
        proxy_set_header Connection "";
        proxy_http_version 1.1;
    }
    
location /jeedom/ {
        proxy_pass http://192.168.0.11;

        proxy_set_header Host $host;
        proxy_set_header Connection "";
        proxy_http_version 1.1;
    }</pre><p></p>
<p>Ainsi, en fonction du “path” demandé, un service différent me répondra :</p>
<ul>
<li><a href="https://&lt;mon_nom_DNS&gt;/constellation">https://&lt;mon_nom_DNS&gt;/constellation</a> : réponse du serveur Constellation</li>
<li><a href="https://&lt;mon_nom_DNS&gt;/zm">https://&lt;mon_nom_DNS&gt;/zm</a>  : réponse du serveur ZoneMinder</li>
<li><a href="https://&lt;mon_nom_DNS&gt;/jeedom">https://&lt;mon_nom_DNS&gt;/jeedom</a> : réponse du serveur Jeedom</li>
</ul>
<p><u>Attention</u> : si le serveur Constellation répond sur un “sous path”, comme ici “/constellation” il faut également modifier la configuration du serveur Constellation pour l’informer.</p>
<p>Pour cela modifiez le ficher “<em>/opt/constellation-server/Constellation.Server.exe.config</em>” :</p>
<p></p><pre class="crayon-plain-tag">sudo nano /opt/constellation-server/Constellation.Server.exe.config</pre><p></p>
<p>Et modifier le <em>listenUri</em> pour reprendre la même structure d’URI, ici en ajoutant “/constellation” :</p>
<p></p><pre class="crayon-plain-tag">&lt;listenUris&gt;
    &lt;uri listenUri="http://+:8088/constellation" /&gt;
&lt;/listenUris&gt;</pre><p></p>
<p>Pour finir, il faudra relancer le service Constellation pour prendre en compte ce changement :</p>
<p></p><pre class="crayon-plain-tag">sudo supervisorctl restart constellation-server</pre><p></p>
<p>Voilà votre Constellation répond maintenant sur le /constellation, dans notre cas <a title="https://demo.internal.myconstellation.io/constellation" href="https://demo.internal.myconstellation.io/constellation">https://demo.internal.myconstellation.io/constellation</a> :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-7.png"><img class="colorbox-5890"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="Constellation derrière Nginx" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-6.png" alt="Constellation derrière Nginx" width="484" height="290" border="0" /></a></p>
<p align="left">Si maintenant on change le path pour “/zm” soit ici <a href="https://demo.internal.myconstellation.io/zm">https://demo.internal.myconstellation.io/zm</a>, c’est notre serveur ZoneMinder qui répondra :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-8.png"><img class="colorbox-5890"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="ZoneMinder derrière Nginx" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-7.png" alt="ZoneMinder derrière Nginx" width="484" height="290" border="0" /></a></p>
<p>On a donc un seul serveur en frontal, Ngnix qui écoute en HTTPS avec le certificat Let’s Encrypt pour sécuriser TOUS les échanges et qui, selon le “path” demandé, transféra les requêtes vers les différents services internes de votre réseau.</p>
<p>A noter que vous pouvez également utiliser des expressions régulières (regex) pour définir vos “locations”. Pour plus d’information : <a title="https://www.scalescale.com/tips/nginx/nginx-location-directive/" href="https://www.scalescale.com/tips/nginx/nginx-location-directive/">https://www.scalescale.com/tips/nginx/nginx-location-directive/</a></p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/constellation-platform/constellation-server/exposer-constellation-en-https-derriere-un-reverse-proxy-avec-nginx-et-lets-encrypt/">Exposer Constellation en HTTPS derrière un reverse proxy avec Nginx et Let&rsquo;s Encrypt</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/constellation-platform/constellation-server/exposer-constellation-en-https-derriere-un-reverse-proxy-avec-nginx-et-lets-encrypt/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[SendMessageProxy]]></category>
		<category><![CDATA[MessageScope]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[Messaging]]></category>
		<category><![CDATA[MessageContext]]></category>
		<category><![CDATA[Proxy]]></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:02:02 by W3 Total Cache
-->