<?xml version="1.0" encoding="utf-8" standalone="no"?><rss xmlns:betag="https://blogengine.io/schemas/tags" xmlns:blogChannel="http://backend.userland.com/blogChannelModule" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" version="2.0">
  <channel>
    <title>Dot.Blog</title>
    <description>Consulting DotNet C#, XAML, WinUI, WPF, MAUI, IA</description>
    <link>http://www.e-naxos.com/Blog/</link>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>BlogEngine.NET 3.3.8.0</generator>
    <language>fr-FR</language>
    <blogChannel:blogRoll>http://www.e-naxos.com/Blog/opml.axd</blogChannel:blogRoll>
    <blogChannel:blink>https://www.e-naxos.com/Blog/syndication.axd</blogChannel:blink>
    <dc:creator>Olivier Dahan</dc:creator>
    <dc:title>Dot.Blog</dc:title>
    <geo:lat>0.000000</geo:lat>
    <geo:long>0.000000</geo:long>
    <xhtml:meta content="noindex" name="robots" xmlns:xhtml="http://www.w3.org/1999/xhtml"/><item>
      <title>Workflow IA : Pauses, Reprises et Checkpoints (+ VIDEO)</title>
      <description>&lt;p class="InterTitrePremium"&gt;&lt;span lang="EN-US"&gt;Microsoft Agent Framework En C# : Un Vrai Workflow Doit Pouvoir Attendre Et Reprendre.&amp;nbsp;&lt;/span&gt;Une grande partie des d&amp;eacute;monstrations d&amp;rsquo;agents repose sur une hypoth&amp;egrave;se tacite : le monde coop&amp;egrave;re.&amp;nbsp;&lt;span lang="EN-US"&gt;Tout se passe dans un seul run. Les donn&amp;eacute;es n&amp;eacute;cessaires sont disponibles imm&amp;eacute;diatement. Aucun op&amp;eacute;rateur ne r&amp;eacute;pond plus tard. Aucun syst&amp;egrave;me externe ne retarde la suite. Rien ne s&amp;rsquo;interrompt. Rien ne red&amp;eacute;marre. Dans un tel d&amp;eacute;cor, presque n&amp;rsquo;importe quel encha&amp;icirc;nement para&amp;icirc;t propre. Mais la r&amp;eacute;alit&amp;eacute; est un peu diff&amp;eacute;rente (on s'en doutait !) &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Le probl&amp;egrave;me est que ce d&amp;eacute;cor parfait n&amp;rsquo;existe presque jamais en production.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Dans une application r&amp;eacute;elle, un processus peut &lt;strong&gt;devoir attendre&lt;/strong&gt; une information compl&amp;eacute;mentaire, &lt;strong&gt;d&amp;eacute;pendre d&amp;rsquo;une validation m&amp;eacute;tier&lt;/strong&gt;, &lt;strong&gt;traverser plusieurs &amp;eacute;crans&lt;/strong&gt;, &lt;strong&gt;survivre &amp;agrave; une fermeture d&amp;rsquo;application&lt;/strong&gt; ou&lt;strong&gt; reprendre le lendemain avec des &amp;eacute;l&amp;eacute;ments pendants&lt;/strong&gt;. &amp;Agrave; partir de l&amp;agrave;, la question n&amp;rsquo;est plus seulement : &amp;ldquo;Le syst&amp;egrave;me sait-il r&amp;eacute;pondre ?&amp;rdquo; &lt;em&gt;&lt;strong&gt;La vraie question devient : &amp;ldquo;Le syst&amp;egrave;me sait-il continuer proprement quand le temps r&amp;eacute;el casse le flot ?&amp;rdquo;&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est le sujet de ce billet et surtout de la nouvelle vid&amp;eacute;o consacr&amp;eacute;e &amp;agrave; Microsoft Agent Framework en C#.&lt;/p&gt;
&lt;h2&gt;Le vrai sujet n&amp;rsquo;est pas l&amp;rsquo;approbation humaine (HITL)&lt;/h2&gt;
&lt;p&gt;Pr&amp;eacute;senter ce th&amp;egrave;me comme une simple vid&amp;eacute;o sur la validation humaine (&lt;em&gt;Human-in-the-loop&lt;/em&gt;) serait bien trop &amp;eacute;troit. L&amp;rsquo;approbation n&amp;rsquo;est qu&amp;rsquo;un exemple. &lt;strong&gt;Le sujet r&amp;eacute;el est la continuit&amp;eacute; d&amp;rsquo;ex&amp;eacute;cution.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Autrement dit : &lt;em&gt;comment un workflow peut-il s&amp;rsquo;interrompre sans se d&amp;eacute;grader, attendre sans se perdre, puis reprendre sans reconstruction artificielle du contexte ?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Cette question est beaucoup plus s&amp;eacute;rieuse qu&amp;rsquo;elle n&amp;rsquo;en a l&amp;rsquo;air. Tant qu&amp;rsquo;un syst&amp;egrave;me n&amp;rsquo;est capable d&amp;rsquo;exister que dans une ex&amp;eacute;cution continue et sans friction, il reste proche d&amp;rsquo;une d&amp;eacute;mo. Il peut &amp;ecirc;tre spectaculaire, mais il n&amp;rsquo;est pas encore robuste.&lt;/p&gt;
&lt;p&gt;Un agent sans pause ni reprise est souvent simplement un syst&amp;egrave;me qui suppose un monde parfait.&lt;/p&gt;
&lt;h2&gt;Ce que Microsoft Agent Framework rend int&amp;eacute;ressant&lt;/h2&gt;
&lt;p&gt;L&amp;rsquo;int&amp;eacute;r&amp;ecirc;t de Microsoft Agent Framework, ici, n&amp;rsquo;est pas d&amp;rsquo;ajouter encore un peu d&amp;rsquo;&amp;ldquo;IA&amp;rdquo; &amp;agrave; une application. &lt;em&gt;Son int&amp;eacute;r&amp;ecirc;t est de fournir une structure claire pour g&amp;eacute;rer les interruptions l&amp;eacute;gitimes du processus. D'ailleurs, stricto sensu, ce n'est pas MAF lui-m&amp;ecirc;me qui fournit ce service mais un namespace particulier de la famille des "microsoft.AI.*" dont fait partie MAF bien entendu.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;La vid&amp;eacute;o insiste donc sur une distinction que beaucoup de contenus m&amp;eacute;langent :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la session conversationnelle ;&lt;/li&gt;
&lt;li&gt;l&amp;rsquo;&amp;eacute;tat partag&amp;eacute; ;&lt;/li&gt;
&lt;li&gt;le checkpoint de workflow.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Confondre ces trois notions conduit presque toujours &amp;agrave; une architecture floue.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Une session n&amp;rsquo;est pas un checkpoint.&lt;/li&gt;
&lt;li&gt;Un historique de messages n&amp;rsquo;est pas un instantan&amp;eacute; d&amp;rsquo;ex&amp;eacute;cution.&lt;/li&gt;
&lt;li&gt;Un objet de contexte s&amp;eacute;rialis&amp;eacute; n&amp;rsquo;est pas une reprise de workflow au sens fort.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le &lt;strong&gt;checkpoint&lt;/strong&gt; r&amp;eacute;pond &amp;agrave; une autre exigence : &lt;strong&gt;capturer un &amp;eacute;tat d&amp;rsquo;ex&amp;eacute;cution exploitable, coh&amp;eacute;rent et reprenable&lt;/strong&gt;. D&amp;egrave;s que l&amp;rsquo;on comprend cette diff&amp;eacute;rence, on sort imm&amp;eacute;diatement du cadre &amp;ldquo;chatbot&amp;rdquo; pour entrer dans celui d&amp;rsquo;un processus durable.&lt;/p&gt;
&lt;h2&gt;La d&amp;eacute;monstration choisie : attendre une information externe&lt;/h2&gt;
&lt;p&gt;Le sc&amp;eacute;nario pr&amp;eacute;sent&amp;eacute; dans la vid&amp;eacute;o &amp;eacute;vite volontairement de commencer par l&amp;rsquo;approbation humaine, parce que ce serait r&amp;eacute;ducteur.&lt;/p&gt;
&lt;p&gt;Le workflow traite d&amp;rsquo;abord une demande m&amp;eacute;tier. Il d&amp;eacute;tecte ensuite qu&amp;rsquo;une donn&amp;eacute;e obligatoire manque pour continuer. &amp;Agrave; ce moment-l&amp;agrave;, il &amp;eacute;met une requ&amp;ecirc;te externe, se met en attente, puis reprend lorsque l&amp;rsquo;information lui est fournie.&lt;/p&gt;
&lt;p&gt;Ce sc&amp;eacute;nario est plus fort que l&amp;rsquo;exemple classique d&amp;rsquo;approbation, parce qu&amp;rsquo;il montre une m&amp;eacute;canique g&amp;eacute;n&amp;eacute;rale.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le syst&amp;egrave;me n&amp;rsquo;&amp;eacute;choue pas.&lt;/li&gt;
&lt;li&gt;Le syst&amp;egrave;me ne repart pas de z&amp;eacute;ro.&lt;/li&gt;
&lt;li&gt;Le syst&amp;egrave;me n&amp;rsquo;invente pas une suite fictive.&lt;/li&gt;
&lt;li&gt;Le syst&amp;egrave;me suspend proprement son ex&amp;eacute;cution.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;C&amp;rsquo;est pr&amp;eacute;cis&amp;eacute;ment ce comportement qui distingue un encha&amp;icirc;nement cr&amp;eacute;dible d&amp;rsquo;une simple d&amp;eacute;monstration en flux continu.&lt;/p&gt;
&lt;h2&gt;Le moment d&amp;eacute;cisif : Le checkpoint et le red&amp;eacute;marrage&lt;/h2&gt;
&lt;p&gt;Le passage le plus important de la vid&amp;eacute;o est celui o&amp;ugrave; le workflow est interrompu, sauvegard&amp;eacute;, puis repris apr&amp;egrave;s red&amp;eacute;marrage.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est l&amp;agrave; que le spectateur comprend qu&amp;rsquo;il n&amp;rsquo;est plus devant un simple m&amp;eacute;canisme conversationnel. Il est devant &lt;em&gt;une logique de syst&amp;egrave;me.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Ce point m&amp;eacute;rite d&amp;rsquo;&amp;ecirc;tre dit clairement : relancer un traitement en esp&amp;eacute;rant reconstruire le contexte n&amp;rsquo;est pas une vraie reprise. C&amp;rsquo;est une approximation. Cela peut suffire pour un prototype. Cela devient faible d&amp;egrave;s qu&amp;rsquo;il faut garantir la coh&amp;eacute;rence, auditer le chemin ou r&amp;eacute;int&amp;eacute;grer proprement une r&amp;eacute;ponse arriv&amp;eacute;e plus tard.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Le checkpoint, lui, sert pr&amp;eacute;cis&amp;eacute;ment &amp;agrave; ne pas tricher avec cette continuit&amp;eacute;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Lorsque le processus red&amp;eacute;marre, l&amp;rsquo;objectif n&amp;rsquo;est pas de rejouer artificiellement une conversation ou de recomposer &amp;agrave; la main les conditions d&amp;rsquo;ex&amp;eacute;cution. L&amp;rsquo;objectif est de reprendre le flot avec son &amp;eacute;tat utile, ses attentes pendantes et sa logique d&amp;rsquo;avancement intacte.&lt;/p&gt;
&lt;h2&gt;Pourquoi ce sujet est architectural&lt;/h2&gt;
&lt;p&gt;Beaucoup de discussions autour des agents se concentrent sur le prompt, les outils, les mod&amp;egrave;les ou les performances de sortie. Tout cela compte, &amp;eacute;videmment. Mais ces discussions passent souvent &amp;agrave; c&amp;ocirc;t&amp;eacute; de la question la plus structurante : &lt;em&gt;que devient le syst&amp;egrave;me quand la r&amp;eacute;alit&amp;eacute; m&amp;eacute;tier impose une pause ?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Si votre architecture ne sait pas g&amp;eacute;rer cela, elle reste limit&amp;eacute;e &amp;agrave; des cas heureux.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est pour cette raison que la pause/reprise n&amp;rsquo;est pas un d&amp;eacute;tail d&amp;rsquo;impl&amp;eacute;mentation. &lt;strong&gt;C&amp;rsquo;est une d&amp;eacute;cision d&amp;rsquo;architecture&lt;/strong&gt;. Elle d&amp;eacute;termine si votre syst&amp;egrave;me est capable d&amp;rsquo;&lt;strong&gt;assumer des d&amp;eacute;pendances externes&lt;/strong&gt;, des &lt;strong&gt;validations asynchrones&lt;/strong&gt;, des &lt;strong&gt;interruptions et des reprises sans s&amp;rsquo;effondrer&lt;/strong&gt; dans de la logique ad hoc.&lt;/p&gt;
&lt;p&gt;Il faut n&amp;eacute;anmoins rester rigoureux : si votre besoin tient dans un simple traitement lin&amp;eacute;aire et imm&amp;eacute;diat, ajouter du checkpointing est une erreur. Vous ajouteriez de la complexit&amp;eacute; sans b&amp;eacute;n&amp;eacute;fice r&amp;eacute;el.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Mais lorsque le processus traverse le temps, la pause/reprise cesse d&amp;rsquo;&amp;ecirc;tre un luxe. Elle devient une exigence.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Voir la vid&amp;eacute;o&lt;/h2&gt;
&lt;p&gt;La vid&amp;eacute;o est disponible ici : &lt;a href="https://youtu.be/0Bjq7viODcY" target="_blank"&gt;https://youtu.be/0Bjq7viODcY&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Si vous d&amp;eacute;veloppez en C# et que vous voulez d&amp;eacute;passer les d&amp;eacute;mos qui supposent une ex&amp;eacute;cution continue, ce contenu montre le seuil suivant : celui o&amp;ugrave; l&amp;rsquo;on cesse de raisonner en simple &amp;ldquo;run&amp;rdquo; pour entrer dans la continuit&amp;eacute; de workflow.&lt;/p&gt;
&lt;p class="InterTitrePremium"&gt;&lt;span lang="EN-US"&gt;C&amp;rsquo;est aussi ce qui distingue un syst&amp;egrave;me qui r&amp;eacute;pond d&amp;rsquo;un syst&amp;egrave;me qui tient.&lt;/span&gt;&lt;/p&gt;
&lt;h2 class="InterTitrePremium"&gt;&lt;span lang="EN-US"&gt;Comprendre les Workflows (vid&amp;eacute;o pr&amp;eacute;c&amp;eacute;dente)&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span lang="EN-US"&gt;Pour comprendre cette nouvelle vid&amp;eacute;o il faut comprendre ce que sont les workflows... Mais vous avez de la chance, la vid&amp;eacute;o pr&amp;eacute;c&amp;eacute;dente traite justement de ce que sont ces plannfications algorithmiques destin&amp;eacute;es &amp;agrave; rendre les applications utilisant de l'IA plus robustes en allignement ave les exigences de rigueur et d'audit de tout programme pro mis en production.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span lang="EN-US"&gt;Vous pouvez regarder la vid&amp;eacute;o "&lt;strong&gt;IA en C# : De l&amp;rsquo;Agent au Workflow&lt;/strong&gt;" &amp;agrave; cette adresse :&amp;nbsp;&lt;a href="https://youtu.be/4C-AePnMiHY" target="_blank"&gt;https://youtu.be/4C-AePnMiHY&lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 class="InterTitrePremium"&gt;&lt;span lang="EN-US"&gt;Conlusion&lt;/span&gt;&lt;/h2&gt;
&lt;p class="InterTitrePremium"&gt;&lt;span lang="EN-US"&gt;Deux vid&amp;eacute;os sur les workflows cela peut sembler beaucoup, mais ils sont d'une importance essentielle. Ceux qui visionneront les deux vid&amp;eacute;os comprendront l'int&amp;eacute;r&amp;ecirc;t crucial de ces constructions algorithmiques rationnalisant l'usage des IA dans des processus m&amp;eacute;tier rigoureux.&lt;/span&gt;&lt;/p&gt;
&lt;p class="InterTitrePremium"&gt;Alors pas de blabla inutile, rendez-vous tout de suite sur ma cha&amp;icirc;ne YouTube !&lt;/p&gt;
&lt;p class="InterTitrePremium"&gt;Stay Tuned !&lt;/p&gt;</description>
      <link>http://www.e-naxos.com/Blog/post/MAF-WORKFLOW2</link>
      <author>odahan@e-naxos.com</author>
      <comments>http://www.e-naxos.com/Blog/post/MAF-WORKFLOW2#comment</comments>
      <guid>http://www.e-naxos.com/Blog/post.aspx?id=f194739a-466b-41de-8d26-f50243a21b17</guid>
      <pubDate>sam., 16 mai 2026 14:00:00 +0100</pubDate>
      <category>IA</category>
      <betag:tag>IA</betag:tag>
      <betag:tag>ai</betag:tag>
      <betag:tag>AgentFramework</betag:tag>
      <dc:publisher>Olivier</dc:publisher>
      <pingback:server>http://www.e-naxos.com/Blog/pingback.axd</pingback:server>
      <pingback:target>http://www.e-naxos.com/Blog/post.aspx?id=f194739a-466b-41de-8d26-f50243a21b17</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://www.e-naxos.com/Blog/trackback.axd?id=f194739a-466b-41de-8d26-f50243a21b17</trackback:ping>
      <wfw:comment>http://www.e-naxos.com/Blog/post/MAF-WORKFLOW2#comment</wfw:comment>
      <wfw:commentRss>http://www.e-naxos.com/Blog/syndication.axd?post=f194739a-466b-41de-8d26-f50243a21b17</wfw:commentRss>
    </item>
    <item>
      <title>Créer une API HTTP locale avec Kestrel sans ASP.NET : .NET 9 minimaliste</title>
      <description>&lt;p&gt;Avec .NET 9+, il est possible de cr&amp;eacute;er des serveurs HTTP &lt;strong&gt;ultra-l&amp;eacute;gers&lt;/strong&gt; sans charger toute la stack ASP.NET. Cela permet d&amp;rsquo;int&amp;eacute;grer une API dans une application console ou desktop (WinUI, WPF, etc.), utile pour exposer des traitements IA, des fonctions de contr&amp;ocirc;le, ou une logique m&amp;eacute;tier accessible par d'autres processus.&lt;/p&gt;
&lt;p&gt;Cet article montre comment construire une API auto-h&amp;eacute;berg&amp;eacute;e minimaliste &amp;agrave; l&amp;rsquo;aide de Kestrel et des primitives HTTP de bas niveau.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&#127919; Cas d&amp;rsquo;usage typique&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fournir une interface JSON locale &amp;agrave; une application desktop&lt;/li&gt;
&lt;li&gt;Interagir avec un moteur IA ou une base vectorielle depuis un front local&lt;/li&gt;
&lt;li&gt;Ouvrir une API interne pour automatiser des tests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&#128640; Projet minimal&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Cr&amp;eacute;ez un projet console :&lt;/p&gt;
&lt;pre&gt;dotnet new console -n MinimalApiApp&lt;/pre&gt;
&lt;p&gt;Ajoutez la r&amp;eacute;f&amp;eacute;rence &amp;agrave; Kestrel :&lt;/p&gt;
&lt;pre&gt;dotnet add package Microsoft.AspNetCore.Server.Kestrel&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;⚙️ Code complet d&amp;rsquo;un serveur HTTP en C# (sans controller, sans MVC)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;using Microsoft.AspNetCore.Hosting;&lt;br /&gt;using Microsoft.Extensions.Hosting;&lt;br /&gt;using Microsoft.AspNetCore.Builder;&lt;br /&gt;using Microsoft.AspNetCore.Http;&lt;br /&gt;&lt;br /&gt;Host.CreateDefaultBuilder()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; .ConfigureWebHostDefaults(webBuilder =&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; webBuilder.Configure(app =&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; app.Run(async context =&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (context.Request.Path == "/hello")&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; context.Response.ContentType = "application/json";&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; await context.Response.WriteAsync("{ \"message\": \"Hello from Kestrel!\" }");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; context.Response.StatusCode = 404;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; });&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; });&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; webBuilder.UseUrls("http://localhost:5001");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; })&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Build()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Run();&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&#128225; Tester l&amp;rsquo;API localement&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Dans un navigateur ou via curl :&lt;/p&gt;
&lt;pre&gt;curl http://localhost:5001/hello&lt;/pre&gt;
&lt;p&gt;R&amp;eacute;sultat :&lt;/p&gt;
&lt;pre&gt;{ "message": "Hello from Kestrel!" }&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&#129514; Ajouter une route dynamique avec un param&amp;egrave;tre&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;if (context.Request.Path.StartsWithSegments("/echo", out var remaining))&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var message = remaining.Value.Trim('/');&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; await context.Response.WriteAsync($"Echo: {message}");&lt;br /&gt;}&lt;/pre&gt;
&lt;pre&gt;Appel via : http://localhost:5001/echo/bonjour&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&#128272; S&amp;eacute;curit&amp;eacute; minimale : restreindre l&amp;rsquo;acc&amp;egrave;s local&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Dans certains cas, vous pouvez &amp;eacute;couter uniquement sur 127.0.0.1 :&lt;/p&gt;
&lt;pre&gt;webBuilder.UseUrls("http://127.0.0.1:5001");&lt;/pre&gt;
&lt;p&gt;Cela emp&amp;ecirc;che tout acc&amp;egrave;s ext&amp;eacute;rieur &amp;agrave; la machine locale.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&#129504; Bonnes pratiques&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Toujours d&amp;eacute;finir un Content-Type correct (application/json recommand&amp;eacute;)&lt;/li&gt;
&lt;li&gt;Prot&amp;eacute;ger l&amp;rsquo;API par un token simple si exposition hors localhost&lt;/li&gt;
&lt;li&gt;D&amp;eacute;couper le pipeline avec Map() si les routes deviennent nombreuses&lt;/li&gt;
&lt;li&gt;Ne pas oublier .UseUrls() pour contr&amp;ocirc;ler l&amp;rsquo;exposition&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&#128282; Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Kestrel peut parfaitement servir de micro-serveur local pour des applications .NET qui ont besoin d&amp;rsquo;un point d&amp;rsquo;entr&amp;eacute;e HTTP. En se passant d&amp;rsquo;ASP.NET MVC ou de Razor, on gagne en l&amp;eacute;g&amp;egrave;ret&amp;eacute;, en temps de d&amp;eacute;marrage et en clart&amp;eacute;. Soyons francs, parfois, juste pour exposer une API simple, les choses devenaient plus proches de l'usine &amp;agrave; gaz que d'une simple feature sympa. Car le mod&amp;egrave;le ASP.NET est fait pour beaucoup plus, et &amp;ecirc;tre oblig&amp;eacute; de le tra&amp;icirc;ner avec soi et son projet pour une simple API est overkilling. Gr&amp;acirc;ce &amp;agrave; Kestrel on peut aujourd'hui penser &amp;agrave; cr&amp;eacute;er des API dans des Apps simples. Il faut y penser car la lourdeur d'antan a eu tendance &amp;agrave; nous forcer &amp;agrave; une sorte d'auto-censure ("surtout ne pas se lancer dans ce truc &amp;ccedil;a va me prendre trop de temps"). Il faut r&amp;eacute;apprendre &amp;agrave; s'&amp;eacute;couter et ne pas avoir peur d'ajouter ce type de comportement m&amp;ecirc;me &amp;agrave; de petites ou moyennes applications sans peur du monstre ASP.NET :-) !&lt;/p&gt;
&lt;p&gt;Stay Tuned !&lt;/p&gt;</description>
      <link>http://www.e-naxos.com/Blog/post/ServerHTTPSansASPNET</link>
      <author>odahan@e-naxos.com</author>
      <comments>http://www.e-naxos.com/Blog/post/ServerHTTPSansASPNET#comment</comments>
      <guid>http://www.e-naxos.com/Blog/post.aspx?id=af9a60f9-c67a-4484-bdd0-806c67d8586d</guid>
      <pubDate>ven., 15 mai 2026 14:00:00 +0100</pubDate>
      <category>C#</category>
      <betag:tag>c#</betag:tag>
      <dc:publisher>Olivier</dc:publisher>
      <pingback:server>http://www.e-naxos.com/Blog/pingback.axd</pingback:server>
      <pingback:target>http://www.e-naxos.com/Blog/post.aspx?id=af9a60f9-c67a-4484-bdd0-806c67d8586d</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://www.e-naxos.com/Blog/trackback.axd?id=af9a60f9-c67a-4484-bdd0-806c67d8586d</trackback:ping>
      <wfw:comment>http://www.e-naxos.com/Blog/post/ServerHTTPSansASPNET#comment</wfw:comment>
      <wfw:commentRss>http://www.e-naxos.com/Blog/syndication.axd?post=af9a60f9-c67a-4484-bdd0-806c67d8586d</wfw:commentRss>
    </item>
    <item>
      <title>Utiliser les générateurs de source en .NET 9 : aperçu, usages et exemples</title>
      <description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Avec .NET 9, les g&amp;eacute;n&amp;eacute;rateurs de source (Source Generators) sont devenus un levier essentiel pour automatiser, optimiser ou fiabiliser certaines t&amp;acirc;ches &amp;agrave; la compilation. Ils permettent d&amp;rsquo;injecter du code C# g&amp;eacute;n&amp;eacute;r&amp;eacute; dynamiquement en fonction du contenu du projet, sans d&amp;eacute;pendre du runtime. Comment s'en servir ?&lt;/p&gt;
&lt;p&gt;Dans cet article, je fais&amp;nbsp;le point sur leur fonctionnement, leur int&amp;eacute;gration, et les cas d&amp;rsquo;usage r&amp;eacute;els.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&#129504; Qu&amp;rsquo;est-ce qu&amp;rsquo;un g&amp;eacute;n&amp;eacute;rateur de source ?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Un &lt;strong&gt;Source Generator&lt;/strong&gt; est une extension du compilateur &lt;strong&gt;Roslyn&lt;/strong&gt; qui peut :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Analyser&lt;/em&gt; le code existant (syntaxique ou s&amp;eacute;mantique)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;G&amp;eacute;n&amp;eacute;rer&lt;/em&gt; du code C# (via SourceText) &amp;agrave; inclure &amp;agrave; la compilation&lt;/li&gt;
&lt;li&gt;&amp;Ecirc;tre utilis&amp;eacute; sans modifier manuellement le code source original&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ils n&amp;rsquo;ex&amp;eacute;cutent aucun code &amp;agrave; l&amp;rsquo;ex&amp;eacute;cution (contrairement aux T4 ou &amp;agrave; la r&amp;eacute;flexion).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&#128230; Exemple minimal de g&amp;eacute;n&amp;eacute;rateur&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;[Generator]&lt;br /&gt;public class HelloGenerator : ISourceGenerator&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void Initialize(GeneratorInitializationContext context) { }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void Execute(GeneratorExecutionContext context)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var source = """&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; namespace AutoGenerated {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static class Hello {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static string Message =&amp;gt; \"Hello from generated code!\";&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; """;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; context.AddSource("hello.g.cs", SourceText.From(source, Encoding.UTF8));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;/pre&gt;
&lt;p&gt;Ce g&amp;eacute;n&amp;eacute;rateur produit une classe statique avec une propri&amp;eacute;t&amp;eacute;. On notera que le syst&amp;egrave;me de g&amp;eacute;n&amp;eacute;ration automatique du toolkit MVVM Microsoft utilise ce type de facilit&amp;eacute; pour simplifier l'&amp;eacute;criture du code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&#129514; Exemple complet : INotifyPropertyChanged automatique&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt; Cr&amp;eacute;ation de l&amp;rsquo;attribut personnalis&amp;eacute;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;[AttributeUsage(AttributeTargets.Class)]&lt;br /&gt;public class AutoNotifyAttribute : Attribute { }&lt;/pre&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt; Classe annot&amp;eacute;e c&amp;ocirc;t&amp;eacute; consommateur&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;[AutoNotify]&lt;br /&gt;public partial class Person&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private string _name;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private int _age;&lt;br /&gt;}&lt;/pre&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt; G&amp;eacute;n&amp;eacute;rateur&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;[Generator]&lt;br /&gt;public class AutoNotifyGenerator : ISourceGenerator&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void Initialize(GeneratorInitializationContext context)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; context.RegisterForSyntaxNotifications(() =&amp;gt; new AutoNotifySyntaxReceiver());&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void Execute(GeneratorExecutionContext context)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (context.SyntaxReceiver is not AutoNotifySyntaxReceiver receiver) return;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (var classDecl in receiver.Candidates)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var model = context.Compilation.GetSemanticModel(classDecl.SyntaxTree);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var symbol = model.GetDeclaredSymbol(classDecl);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (symbol is not INamedTypeSymbol namedType) continue;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var ns = namedType.ContainingNamespace.ToDisplayString();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var props = new StringBuilder();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (var member in namedType.GetMembers().OfType&amp;lt;IFieldSymbol&amp;gt;())&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var propName = char.ToUpper(member.Name[1]) + member.Name.Substring(2);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var type = member.Type.ToDisplayString();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; props.AppendLine($"public {type} {propName} {{ get =&amp;gt; {member.Name}; set =&amp;gt; SetProperty(ref {member.Name}, value); }}");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var source = $$"""&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; using System.ComponentModel;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; namespace {ns}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public partial class {namedType.Name} : INotifyPropertyChanged&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public event PropertyChangedEventHandler? PropertyChanged;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected bool SetProperty&amp;lt;T&amp;gt;(ref T storage, T value, [System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (EqualityComparer&amp;lt;T&amp;gt;.Default.Equals(storage, value)) return false;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; storage = value;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {props}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; """;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; context.AddSource($"{namedType.Name}.g.cs", SourceText.From(source, Encoding.UTF8));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class AutoNotifySyntaxReceiver : ISyntaxReceiver&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public List&amp;lt;ClassDeclarationSyntax&amp;gt; Candidates { get; } = new();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void OnVisitSyntaxNode(SyntaxNode syntaxNode)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (syntaxNode is ClassDeclarationSyntax cls &amp;amp;&amp;amp; cls.AttributeLists.Count &amp;gt; 0)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Candidates.Add(cls);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;/pre&gt;
&lt;p&gt;Ce g&amp;eacute;n&amp;eacute;rateur ajoute automatiquement l&amp;rsquo;impl&amp;eacute;mentation de &lt;em&gt;INotifyPropertyChanged&lt;/em&gt; et des propri&amp;eacute;t&amp;eacute;s publiques aux champs priv&amp;eacute;s d&amp;rsquo;une classe annot&amp;eacute;e.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&#128295; Mise en place dans un projet .NET&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Cr&amp;eacute;er un projet de type Analyzer :&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;dotnet new analyzer -n DemoSourceGen&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Ajouter une r&amp;eacute;f&amp;eacute;rence au package Roslyn :&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;dotnet add package Microsoft.CodeAnalysis.CSharp&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Compiler le g&amp;eacute;n&amp;eacute;rateur et r&amp;eacute;f&amp;eacute;rencer le .dll dans un projet consommateur :&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&amp;lt;ItemGroup&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;Analyzer Include="..\DemoSourceGen\bin\Debug\netstandard2.0\DemoSourceGen.dll" /&amp;gt;&lt;br /&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Utiliser le code g&amp;eacute;n&amp;eacute;r&amp;eacute; dans le projet :&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;var person = new Person { Name = "Alice", Age = 42 };&lt;br /&gt;person.PropertyChanged += (s, e) =&amp;gt; Console.WriteLine($"Changed: {e.PropertyName}");p&lt;br /&gt;erson. Name = "Bob";&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&#128218; Cas d&amp;rsquo;usage fr&amp;eacute;quents&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;G&amp;eacute;n&amp;eacute;ration de code pour la s&amp;eacute;rialisation (Json, XML, BSON...)&lt;/li&gt;
&lt;li&gt;Impl&amp;eacute;mentation automatique d&amp;rsquo;interfaces (comme INotifyPropertyChanged)&lt;/li&gt;
&lt;li&gt;Cr&amp;eacute;ation de proxy statiques ou factories&lt;/li&gt;
&lt;li&gt;Code r&amp;eacute;p&amp;eacute;titif (validation, services, mappers...)&lt;/li&gt;
&lt;li&gt;G&amp;eacute;n&amp;eacute;ration de constantes (resx, settings...)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;⚠️ Limitations et points de vigilance&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pas d&amp;rsquo;acc&amp;egrave;s au runtime (aucun appel File.ReadAllText, etc.)&lt;/li&gt;
&lt;li&gt;Compilation plus longue (&amp;agrave; &amp;eacute;quilibrer selon le nombre de fichiers g&amp;eacute;n&amp;eacute;r&amp;eacute;s)&lt;/li&gt;
&lt;li&gt;Complexit&amp;eacute; croissante si mauvaise structuration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Toujours documenter ce que le g&amp;eacute;n&amp;eacute;rateur produit, surtout pour les &amp;eacute;quipes... (et pour soi-m&amp;ecirc;me car revenir un an apr&amp;egrave;s sur un code qu'on a &amp;eacute;crit est parfois aussi n&amp;eacute;buleux que de regarder le code d'un autre si tout n'a pas &amp;eacute;t&amp;eacute; fait dans les r&amp;egrave;gles et document&amp;eacute; !).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&#129513; Environnement et outils&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Compatible avec Visual Studio, Rider, VS Code (IntelliSense fonctionne sur le code g&amp;eacute;n&amp;eacute;r&amp;eacute;)&lt;/li&gt;
&lt;li&gt;Diagnostic via GeneratorExecutionContext.ReportDiagnostic&lt;/li&gt;
&lt;li&gt;D&amp;eacute;bogage possible via Debugger.Launch() dans Execute()&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&#128282; Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Les g&amp;eacute;n&amp;eacute;rateurs de source en .NET 9 permettent d&amp;rsquo;automatiser des pans entiers de code r&amp;eacute;p&amp;eacute;titif ou optimis&amp;eacute;. Ils favorisent la maintenabilit&amp;eacute;, la performance et l&amp;rsquo;&amp;eacute;volution de vos architectures.&lt;/p&gt;
&lt;p&gt;Stay Tuned !&lt;/p&gt;</description>
      <link>http://www.e-naxos.com/Blog/post/GenSource</link>
      <author>odahan@e-naxos.com</author>
      <comments>http://www.e-naxos.com/Blog/post/GenSource#comment</comments>
      <guid>http://www.e-naxos.com/Blog/post.aspx?id=14b0d203-e9f3-469c-8916-ab2b8381be16</guid>
      <pubDate>ven., 8 mai 2026 14:00:00 +0100</pubDate>
      <category>C#</category>
      <betag:tag>c#</betag:tag>
      <dc:publisher>Olivier</dc:publisher>
      <pingback:server>http://www.e-naxos.com/Blog/pingback.axd</pingback:server>
      <pingback:target>http://www.e-naxos.com/Blog/post.aspx?id=14b0d203-e9f3-469c-8916-ab2b8381be16</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://www.e-naxos.com/Blog/trackback.axd?id=14b0d203-e9f3-469c-8916-ab2b8381be16</trackback:ping>
      <wfw:comment>http://www.e-naxos.com/Blog/post/GenSource#comment</wfw:comment>
      <wfw:commentRss>http://www.e-naxos.com/Blog/syndication.axd?post=14b0d203-e9f3-469c-8916-ab2b8381be16</wfw:commentRss>
    </item>
  </channel>
</rss>