Onyx Solution – Une Mini-Formation sur l’Architecture Logiciel

Onyx Solution https://github.com/YannVasseur35/Onyx Onyx Solution Une solution Microsoft .net 7.0 / C# permettant l’apprentissage de concepts de software design, d’architecture, de clean code, de tests… Permet de partir sur de bonnes bases pour un petit/moyen projet, basé sur quelques années d’expériences dans le software design. Onyx est une pierre précieuse de couleur noire. J’ai donnée ce nom à ce projet d’apprentissage car il est court, facilement identifiable, abstrait, et j’aime bien donner des « noms de code » à un projet. On va prendre comme exemple une application de météo (qui est d’ailleurs l’exemple par défaut d’une application .net web) on aura donc Une API qui expose des données une base de données SQLite avec EntityFramwork (code first) Une clean architecture avec de nombreux tests + code coverage CI/CD avec une pipeline AzureDevops Introduction On a tous commencé par écrire un seul projet c# et tout mettre dedans, sans vraiment rien structurer. Alors oui, ça marche et honnêtement vu les ambitions de cette app méteo c’est ce que l’on devrait faire. Et puis comme tout bon projet, il évolue, en quelques années tout un tas de nouvelles fonctionnalités se sont ajoutés, plusieurs devs sont passés dessus, avec du code plus ou moins clair. De plus avec le temps, l’infrastructure a changé, on a fait évoluer la base de données, certain services sont directement sur le cloud et on a du faire face à de la montée en charge. On a du « scaler » l’application, recoder des parties, ajouter du cache etc…Et bien entendu rien n’est testé automatiquement. Bref la vie d’une application dans pas mal de boite en France et ailleurs dans le monde. Je développe avec .net depuis plus de 20 ans. Et j’ai vu un certain nombre d’application (un bon paquet à vrai dire) finir dans ce que l’on appelle un « monolith legacy », très très dure à maintenir. Ces applications existent encore à l’heure ou j’écris ces lignes. Parfois on en est au deuxième projet de « refonte ». Un cas typique est celui du projet ou l’on retrouve toute la logique métier dans les procédures SQL. Car c’est ce qui faisait vraiment gagner en pref à l’époque (et encore aujourd’hui). Mais seule la personne en charge de ces procédures stockées, souvent indéchiffrable et intestable, est en mesure de travailler dessus. Autre cas bancale, on a de la logique métier dans les pages web. Du coup on se retrouve à gérer à plusieurs endroits, du code qui fait plus ou moins la meme chose, au risque qu’un jour il ne fasse plus la même chose ! Heureusement aujourd’hui on a énormement plus de techniques, d’outils et de services qui permettent d’appréhender les projets autrement. Les entreprises comprennent les enjeux et les risques de garder trop longtemps du code legacy en production et s’engagent dans de gigantesque chantier de « renovation » voir même de ré-écriture complète. J’ai moi aussi contribuer à ces erreurs et je contribue aussi à leurs résolutions. Ce projet tente modestement de répondre à certaines problématiques couramment vues en entreprise. Je ne prétends pas tout résoudre mais apporter quelques réponses à des questions que moi même je me suis posé. Et à vrai dire, le meilleurs moyen d’y répondre pour moi est de tenter de le faire comprendre à quelqu’un d’autre. J’ai donc entrepris ce projet Onyx. Progression Vous avez deux façons de voir les choses : la rapide. Restez sur la branche master, la plus à jour et dernière en date. Vous avez tout le code source et tous les tests. Regardez le code et inspirez-en vous, prennez ce qui vous intéresse. l’apprentissage. Ce sera plus lent, mais j’explique tous les concepts pas à pas. On démarre gentillement et on progresse par étape (step). C’est une sorte de TP (travaux pratique) qu’on faisait à l’école. Pour suivre ce TP il faudra « naviguer » avec Git de branche en branche. C’est simple, toutes les branches s’appellent ‘step’ suvit d’un numéro. Chaque step aura sa propre doc (ex: step2.md). Suffit de s’y référer pour comprendre ce qu’y a été fait à chaque étape. Sommaire Step1 : Structure de solution Step2 : Premier endpoint Api Step3 : Test endpoint Api Rest Step4 : Application Service et Tests Step5 : DataService et Tests Step6 : Mapping et Tests Step7 : ORM (Entity Framework) et Tests Step8 : Entity Framework Step9 : Finalisation de la chaine de données Step10 : Code Coverage Step11 : CRUD : Implémentation et Tests Step12 : Tests d’intégration Step13 : CI/CD AzureDevops Pipeline Step14 : Pipeline avec Code Coverage Git Repo : https://dev.azure.com/ReactorLab/_git/Onyx Vous devrez connaitre quelques commandes git de base très simple pour « naviguer » dans les branches de ce repo. Pour changer de branche : git checkout step1 Si vous avez fait des modifications et que vous souhaitez changer de branche, git va vous obliger à faire un commit ou à vous débarraser de ces changements. Comme vous ne contribuez pas au projet, débarrassez vous de vos changements avec la commande stash, puis faites votre checkout git stash git checkout step2 Documentations Annexes Vous trouverez des informations complémentaires sur différents concept d’architecture ici (en anglais): Main Architecture Hexagonal Architecture DDD CQRS AND ES SOLID Tout est dans le répertoire docs.

Signoz et OpenTelemetry avec une app .net sous linux

Disclamer A l’heure ou j’écris cet article, le code source d’OpenTelemetry et Signoz sont en alpha/beta/pre-release.  Certaine lib sont en release officielle. J’édite au fur et à mesure certaine infos. Le code évolue et cet article aussi.  Il n’est certainement plus « à la page » lorsque vous lirez ces ligne.  Et de même, la doc officielle, celle de Microsoft et les ReadMe des repos ne sont pas tous mis à jours en temps et en heure.  C’est un sujet chaud pattate !!! Besoins Comme d’habitude, j’écris un article avec un vrai besoin et une application dans la vraie vie.  J’ai un serveur en prod et je souhaite le monitorer pour : observer son comportement (nombre de requêtes, % de CPU/RAM/Disk, periode d’activité/repos etc) analyser des problèmes, avoir accès aux logs sans ouvrir un terminal être alerté en cas de problème et pouvoir définir ces alertes avoir une vue d’ensemble avec des KPI de base   Contexte Depuis peu (qq années) on a la possibilité de faire tourner du .net sous linux. Ca change quoi allez vous me dire ?  Personnelement une question de coût. Un VPS (virual private server) sous linux c’est au moins deux fois moins cher que sous Windows (ça dépend avec quel fournisseur et les prix ont aussi évolué dans le temps). Mais aujourd’hui un VPS linux est utlra compétitif. Et j’ai pas de besoin cloud (même si j’y pense). Avec Windows on était habitué à installer des outils graphiques supplémentaires. Et meme de base on avait des outils de monitoring. Sous linux, c’est moins évident car on utilise principalement la ligne de commande. Et personnellement j’y retrouve pas mon compte. Même si on peut aussi mettre une interface graphique, c’est pas le but d’un serveur. Enfin, je voudrais pouvoir consulter ceci sans me loguer en ssh (depuis une interface web) et avoir des alertes email et sms serait top.  Actuellement je développe un nouveau produit (https://outquest.fr). Celui ci comporte un site web (game) et un site backoffice (qg). Le site officiel (outquest.fr) et le shop sont hébergés ailleurs (planethoster). J’ai une prod et un staging. (donc 4 site webs au final). J’ai commencé avec un serveur low cost à 2.99€/mois (Debian, 1 core,  2 Go Ram, 25Go SSD …) chez Ikoula. Franchement à ce prix la, ça marche bien pour faire tourner 4 sites webs.(avec que moi dessus hein !) Ces 4 sites web tournent sous 4 services kernel (autorestart) linux et géré par un serveur web frontal NGinx.  –> pour la config voir cet article J’ai de plus une CI/CD géré par azure devops (voir article Azure Devops) qui me permet via des pipelines de deployer automatiquement mon code sur les serveurs web respectif à chaque push git sur mes branches dev et master.  Ca a dla gueule ! Pour un mec tout seul (pour le moment) je sors la grosse artillerie. J’aurais pu partir direct avec un site web en prod et debuger dessus à l’ancienne. Mais j’aime bien apprendre à faire les choses bien :). Et justement, pour faire bien, la prochaine étape c’est le monitoring des serveurs (ya aussi les backups, je pense que j’en ferai un article à part).  Du coup j’ai voulu tester une solution qui me paraissait pas mal, un APM (Application Performance Management) : CheckMK.  Le souci c’est que j’ai vu trop gros (ce machin permet de gérer tout un parc informatique, plusieurs serveurs, node, kubernetes…) Et en l’installation, le machin à fait fondre mon serveur. Plus moyen d’y accéder pendant un temps et pas moyen de le redémarrer (j’ai contacté le support, ce qui m’a pris plusieurs jours, à ce prix la fallait pas attendre des miracles.) Le bon moment pour passer à un niveau supérieur.  A ce stade j’avais ma prod et mon staging sur la meme petite bécanne. Du coup je me dis qu’il faudra quand meme passer sur qq chose de plus sérieux pour la prod. J’ai donc opté pour un VPS OMGServ avec cette config :  Et une option payante supplémentaire de backup. (snapshots) CheckMK tourne déjà beaucoup mieux, mais comme je le disais c’est pas une solution pour moi. Ca install une bardé de trucs dont Apache2, qui fout la merde avec mon Nginx.  Après qq recherches, je suis tombé sur Signoz et OpenTelemetry. Et c’est ce qu’il me faut !   Signoz   Signoz est une interface web permettant de visualiser un ensemble de données sur votre serveur linux.  C’est une solution Open Source, récente et encore en dev. C’est un concurrent à DataDog (payant).  Elle permet de monitorer des applications et de fournir des éléments pertinents pour les devops.  Cette solution naît d’un constat. Les équipes techniques sont frustrées d’utiliser pleins d’outils différents provenants de sources de données elles aussi différentes pour voir leurs logs/metrics/traces …   De plus les outils existants sont « lourds », taillé pour de la grosse boite (faut bien vendre) avec des standards propriétaires et non générique.  Je n’ai pas de recul suffisant mais mon sentiment c’est que c’est compliqué et qu’un outil simple, uniformisé gratuit et open source manquait à ce niveau pour un niveau « intermediaire » (PME, TPME, indé) Un standard est en train d’émerger concernant toute ces données que l’on appelle OpenTelemetry. OpenTelemetry Encore un nouveau framework ? C’est quoi, une couche de plus ? OpenTelemetry c’est une collection d’outil, d’APIs et de SDKs permettant de mesurer, generer, collecter et exporter des données de télémetrie (metrics, logs et traces) afin de mieux analyser le comportement et les performances de nos applications.  Super mais qui porte le truc ? Est ce que c’est un projet qui va être adopté ? Oui, en tout cas par Microsoft : https://learn.microsoft.com/en-us/azure/azure-monitor/app/opentelemetry-overview Vu l’investissement de Microsoft pour les projets à succès Open Source, et vu le besoin, je pense qu’OpenTelemetry a de l’avenir.  Installer Signoz Il existe plusieurs façon d’installer Signoz, j’ai choisi pour ma part la version Standalone (https://signoz.io/docs/install/docker/) sur mon VPS linux Debian 11. Vous devrez télécharger le repo git : git clone -b main https://github.com/SigNoz/signoz.git puis vous rendre dans le répertoire suivant :…

Package Blazor

Communauté Même si j’expose pas mal de trucs au reste du monde (articles, démo, tutos…) j’ai jamais vraiment « contribué » à la communauté via des projets open source. Jusqu’à peu.  Faut bien commencer 🙂 En vrai, je m’en faisais tout une montagne. Pour moi faire un package nuget était compliqué. J’avais tord. En fait ça n’a rien de compliqué. Ce qui est vraiment chaud, c’est de gérer la maintenance et « animer » la communauté (répondre aux questions, faire un readme, corriger etc.) Blazor Je travaille sur un projet avec la techno Blazor depuis quelques mois. Je kiffe.  C’est un projet WASM. Donc qui utilise la WebAssembly. Pour moi c’est le futur. Je pense qu’on va vite se passer de Javascript d’ici 5 ans. Personnellement j’en ai plein le cul de ce language. Par contre respect, il a contribué à rendre nos app web carrément plus sympas.  Et donc on peut pas encore s »en passer vraiment, car l’essentiel des supers libs d’aujourd’hui son écrite en JS. Même si certain éditeur commence à sortir des versions WebAssembly. Mais c’est encore trop rare.  Donc faut encore faire avec. Et Blazor permet de faire un pont entre notre code C# et Javascript.  Ok certain vont me dire, à quoi ça sert, autant tout faire sur du JS. Oui. Mais sans moi, pour les raisons du dessus. Donc moi je veux faire du C#. Alors comment faire ? Faut coder un wrapper qui va nous servir d’intermediaire.  Mon premier package nuget J’avais besoin d’un lecteur de QR code dans mon appli. J’ai cherché et j’ai rien trouvé sur le gestionnaire de package Nuget. Alors j’ai décidé de faire le mien. Et puis je me suis dit que ce serait sympas de le partager. Et ça donne ça : Repo Github : https://github.com/YannVasseur35/ReactorBlazorQRCodeScanner Package Nuget : https://www.nuget.org/packages/ReactorBlazorQRCodeScanner/ Création d’une librairie Blazor La première chose à faire est de créer un nouveau projet « Bibliothèque de classes Razor » Si on ouvre le fichier projet, voici ce que j’ai  <Project Sdk= »Microsoft.NET.Sdk.Razor »> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> <ItemGroup> <SupportedPlatform Include= »browser » /> </ItemGroup> <ItemGroup> <PackageReference Include= »Microsoft.AspNetCore.Components.Web » Version= »6.0.11″ /> </ItemGroup> </Project> Composition d’une lib razor (blazor) Voici un exemple de projet vide : Si on analyse une lib razor, voici ce qu’on y trouve : Component1.razor C’est votre composant visuel qui sera afficher dans vos pages. Suffira d’appeler <Component1/> dans votre page razor. Il affichera un cadre par défaut. A vous de customiser votre composant pour qu’il affiche ce que vous voulez qu’il affiche.  ExampleJsInterop.cs Comme son nom l’indique, c’est un exemple de ce que vous pouvez faire à minima avec du code C# qui utilise du javascript. Dans son contructeur : private readonly Lazy<Task<IJSObjectReference>> moduleTask; public ExampleJsInterop(IJSRuntime jsRuntime) { moduleTask = new(() => jsRuntime.InvokeAsync<IJSObjectReference>( « import », « ./_content/RazorClassLibrary1/exampleJsInterop.js »).AsTask()); } On voit que ça charge un fichier js. Notez aussi le chargement « Lazy » qui va permet de ne charger les éléments de notre lib qu’au moment où c’est nécessaire.  https://learn.microsoft.com/en-us/aspnet/core/blazor/webassembly-lazy-load-assemblies?view=aspnetcore-7.0 Donc quelque part, si vous n’utilisez pas le composant dans vos premières pages, il ne sera pas chargé (téléchargé pour le client). S’en suis dans le code une seule méthode : public async ValueTask<string> Prompt(string message) { var module = await moduleTask.Value; return await module.InvokeAsync<string>(« showPrompt », message); } Ici on nous présente un méthode très simple pour afficher un prompt JS. On appelle, via module.InvokeAsync la méthode javascript « showPrompt » et on lui passe un paramètre « message ».  exampleJsInterop.js export function showPrompt(message) { return prompt(message, ‘Type anything here’); } Le code JS est super simple. On lance un prompt tout bête avec le message qu’on a en paramètre. Voilà pour la présentation d’un composant blazor.  Intégration Maintenant que l’on a un composant blazor on va l’utiliser dans notre app web WASM.  Suffit d’ajouter une référence de projet dans notre projet client. ensuite dans une page, par exemple index.razor, on ajoute ceci :  @page « / » @using RazorClassLibrary1 <Component1 /> Visuellement ça donnera ceci : Ajoutons un peu de code à notre page pour jouer avec un bouton : @page « / » @using RazorClassLibrary1 @inject IJSRuntime _jSRuntime <Component1/> <button onclick= »@Show() »>Click me</button> @code{ private ExampleJsInterop? _exampleJsInterop; protected override void OnInitialized() { _exampleJsInterop = new ExampleJsInterop(_jSRuntime); } protected async Task Show() { await _exampleJsInterop.Prompt(« coucou »); } } On vient de lancer du js avec du C#. Scanner de QR Code. Pour revenir à mon besoin initiale, je dois pouvoir scanner un QR Code. Ya pas encore de lib nuget mais y’en a quelques une sous javascript, dont jsQR https://github.com/cozmo/jsQR La lib peut faire plein de chose, moi j’ai besoin de récuperer que la lecture du code QR. Pour cela j’ai ajouté une Action (delegate) à mon composant pour que lorsque le JS trouve un QR code et arrive à le lire, cela déclanche (un Invoke) une méthode dans mon code. Le but n’est pas de décrire comment j’ai fait, le code source est dispo ici : https://github.com/YannVasseur35/ReactorBlazorQRCodeScanner J’ai bossé comme avec le précendent projet, en « local » à savoir que mon projet « lib blazor » est ajouté à mon projet blazor client.  Pour que ce soit plus simple, pour moi et pour le reste du monde, il faudrait faire un package nuget et l’importer depuis nuget.org   Le Package Et c’est la que je me faisait tout une montagne (alors que c’est plus simple que de publier une app Android ou pire Apple). Il suffit de taper une commande : dotnet pack Et c’est tout 🙂 Bien entendu il faut aussi donner quelques informations sur le package. Ceci est fait dans le fichier projet de la bibliothèque de classe razor. Voici ce que j’ai mis pour mon package de scan de QR code. <Project Sdk= »Microsoft.NET.Sdk.Razor »> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> <PackageId>ReactorBlazorQRCodeScanner</PackageId> <Version>1.0.5</Version> <Authors>Yann Vasseur</Authors> <Company>reactor.fr</Company> <PackageTags>Blazor;Reactor;QRCode;ScannerQR Code</PackageTags> </PropertyGroup> <ItemGroup> <SupportedPlatform Include= »browser » /> </ItemGroup> <ItemGroup> <PackageReference Include= »Microsoft.AspNetCore.Components.Web » Version= »6.0.4″ /> </ItemGroup> </Project> Et bim on a un fichier ReactorBlazorQRCodeScanner.1.0.5.nupkg dans votre bin/debug Push sur nuget.org Pour publier en ligne, il vous faut un compte sur nuget.org. Ensuite il va vous falloir une clé api. https://www.nuget.org/account/apikeys Quand c’est fait, il restera une étape, taper cette commande (dans le dossier ou se trouve votre package) dotnet nuget push…

Azure Devops Pipeline (CI/CD) – Environnement

Problème du dernier post Je me suis bien pris la tête sur le dernier billet au sujet d’un nouveau problème qui est apparu lorsque j’ai voulu diviser mon site web en 2, une partie staging et une partie prod. Ca pourrait tout aussi bien être "preprod", "recette" etc… Avant j’avais qu’un seul site web: blazordemo.reactor.fr. Celui ci a sa config Nginx et son service systemd qui fait tourner Kernel via un proxy sur le port 7777. (voir article ) J’en ai créé un nouveau "staging.blazordemo.reactor.fr".  L’idée est de faire comme les pros, un site web de "staging" et un de "prod".  dev : locale, tambouille de developeur, avec une base de données crado, des machins bricolés, des trucs à jours ou pas… staging:  distante, même environnement que la prod (meme serveur de base de données, même OS, même TOUT, sauf les données qui sont normalement copiés et anonymisés dans le meilleurs des mondes) prod: distante, le site qu’on update le vendredi soir 🙂 Donc j’ai crée "staging.blazordemo.reactor.fr". Sauf que j’ai pas modifié mon service qui fait tourner Kestrel via proxy sur port 7777.  Et j’ai mis un temps fou à m’en apercevoir. (j’ai été jusqu’a faire un gros delete de mon repertoire www. Nginx continuait à me servir un beau site web… même après un reboot. car le service était le meme…) Donc il me faut 2 services… Un de staging, l’autre de prod. Le tout sur un port proxy différent bien évidement.  Bien entendu, ce problème n’existe pas si le staging et la prod ne sont pas sur le meme serveur, ce qui est TRES recommandé. Cependant, je trouve l’exercice intéressant car il pousse dans les retranchements et force à de bonnes pratiques. Mon ancienne technique Dans le projet Blazor Server, dans Program.cs j’ajoutais ceci  Une ligne de compilation conditionnelle qui me changait le port si on était en release (ce que je considèrais comme mon unique prod).  Je pourrais ajouter une condition STAGING avec un port 7776 et m’en servir pour la version staging. A mon sens une directive de compilation n’a rien a voir avec les environnements, je veux dire c’est liés, mais c’est pas son but de définir du paramétrage de port…  Je pense qu’on peut faire mieux, avec les fichiers de conf appsettings.js. Créeons deux autres fichiers de config, un pour la prod et l’autre pour le staging. Normalement vous avez déjà par défaut un fichier appsettings.Development.json launchSettings.json Si vous travaillez avec Visual Studio ou VS Code vous devez savoir que vous avez des options de lancement de votre app qui sont configurable dans le fichier Properties/launchSettings.json Encore un fichier de config qui sème le doute… { « iisSettings »: { « windowsAuthentication »: false, « anonymousAuthentication »: true, « iisExpress »: { « applicationUrl »: « http://localhost:54778 », « sslPort »: 44382 } }, « profiles »: { « BlazorDemo.Server »: { « commandName »: « Project », « dotnetRunMessages »: true, « launchBrowser »: true, « inspectUri »: « {wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri} », « applicationUrl »: « https://localhost:7249;http://localhost:5249 », « environmentVariables »: { « ASPNETCORE_ENVIRONMENT »: « Development » } }, « IIS Express »: { « commandName »: « IISExpress », « launchBrowser »: true, « inspectUri »: « {wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri} », « environmentVariables »: { « ASPNETCORE_ENVIRONMENT »: « Development » } } } } Comme on peut le voir dans la section "profiles", je peux lancer mon app soit : Via IIS Express  Via la commande dotnet run La première est historique, je pense qu’on en parlera plus dans qq temps. Avant .net core on était obliger de lancer un server utilisant le .net Framework sous IIS qui est le serveur de Windows. La version Express est la version de dévelopement. Pour moi c’est voué à mourrir, mais certains ont des habitudes et Microsoft les forces pas à les changers.  Depuis .net Core (et donc .net 5 et 6), on peut executer nos app sur n’importe quel OS et serveur web comme apache ou nginx sous linux. On a un serveur web intermédiaire appelé Kestrel qui fait le job. D’ailleurs c’est lui que l’on utilise en dévelopement.  En executant une commande dotnet run sur notre projet serveur, on lance un Kestrel. C’est lui que l’on veut paramétrer pour avoir une config dev, staging, prod.  C’est possible d’éditer en développement ce fichier pour changer de port. Mais c’est uniquement un fichier de conf pour une execution en dev local. C’est pas un fichier de configuration plateforme de prod.  Je place ça là car c’est un fichier qui peut vous semer le doute lors de vos devops et test local. AppSettings.{ENV}.json On va modifier le fichier appSettings.Developement.json et lui rajouter ceci  { « Plateform »: « Dev », « Kestrel »: { « EndPoints »: { « Http »: { « Url »: « http://localhost:1234 » } } }, « Logging »: { « LogLevel »: { « Default »: « Information », « Microsoft.AspNetCore »: « Warning » } } } Perso je rajoute une ligne "Environment" qui me permet de voir dans sur quel type d’environement je suis (et plus tard de l’afficher dans l’app).  Ce qui nous intéresse c’est la section Kestrel. On ajoute un EndPoints et on lui précise un port.  Faites un dotnet run sur votre projet à présent : On a un warning qui nous dit que l’adresse utilisé va écrasé celle du launchsetting.json. C’est ce qu’on veut. On voit bien la nouvelle adresse http://localhost:1234.  C’était pour la démo, en dev ça sert a rien de faire cela, autant utiliser le launchSettings.json qui est la pour ça. Donc enlever la ligne Kestrel, c’était pour la démo. Par contre on va mettre ces configs pour appsettings.staging.json  { « Plateform »: « Staging », « Kestrel »: { « EndPoints »: { « Http »: { « Url »: « http://localhost:7776 » } } }, « Logging »: { « LogLevel »: { « Default »: « Information », « Microsoft.AspNetCore »: « Warning » } } } et appsettings.prod.json { « Plateform »: « Prod », « Kestrel »: { « EndPoints »: { « Http »: { « Url »: « http://localhost:7777 » } } }, « Logging »: { « LogLevel »: { « Default »: « Information », « Microsoft.AspNetCore »: « Warning » } } } ASPNETCORE_ENVIRONMENT Encore une chose à savoir. Pour déterminer sur quel environement .net se trouve, il utilise une variable d’environement ASPNETCORE_ENVIRONMENT Elle est d’ailleurs clairement définie dans le fichier launchSettings.json à "Development". Donc en dev, le fichier de config appsettings utilisé sera appsettings.development.json Pour que ce mécanisme fonctionne en prod, soit on définie la variable ASPNETCORE_ENVIRONMENT à "Production" soit par défaut, si elle n’existe pas, c’est déjà le cas (attention moi j’ai nommé mon appsettings prod et non production). Le problème c’est que une variable d’environement est définie pour tout…

Azure Devops Pipeline (CI/CD) – Versioning

C’est quoi une version ? Je vais faire quelque chose de très basique et qui ne sera probablement pas appliqué tel quel dans un cas plus professionnel. D’ailleurs, chacun ayant ses méthodes de travail, ce post reste un example de "comment on pourrait faire" pour versionner une app.  C’est quoi une version ? La encore, je suis pas sûr que tout le monde utilise la même façon de versionner.  Par exemple les versions du navigateur Firefox utilise simplement un chiffre (https://blog.mozfr.org/pages/Calendrier-versions-Firefox). Mais si on regarde de plus prêt on a quand meme 98.0.1 et donc des points de séparations.  En fait, Pour le grand public on va utiliser "Firefox 98". Mais il faut savoir qu’il existe de nombreuses versions de la 98 ! Du moins en interne. Avant de livrer une version patché 98.0.1 qui va corrigé des bugs mineures.  D’après ce que j’ai pu voir, on utilise principalement ce style de nommage de version X.Y.Z X : Version Majeure (non rétro compatible) (nouvelles fonctionalités, gros correctif, ajout de techno, changement de look…) Y : Version Mineure (rétro compatible) (correctifs, patchs, en gros pas de grosse modif, mais qui répare) Z : Révisions.  (rétro compatible) Sert plutot au dev et product owner pour savoir de quelle version on parle en pre prod pour basculer vers la prod. Quelque part, ce dernier numéro ne devrait à mon sens pas être communiqué officiellement (un peu comme Firefox qq part) Sur la version X, on a je pense tous la même idée. On sort une version X rarement. Par contre, je suis pas certain qu’on utilise tous Y et Z de la même manière. Franchement, c’est freestyle, dans les versions mineures on peut voir de nouvelles (petites) fonctionalités. C’est vraiment selon vos préférences et ceux avec qui vous bosser.  Pour le coté retro compatible, c’est ce que j’ai lu sur le net. Intéressant mais pas du tout respecté par tous.  Autre style, voici un format intéressant ou l’on cumule en plus une date : V 2020.10.23.1629 Je trouve ce format particulièrement intéressant car on sait tout de suite de quand date la version. Mais ca fait bcp de chiffre.  Ce format est utilisé par Larsen Lance avec un scipt powershell qui "incrémente" ce format à chaque build en automatique (http://www.lancelarsen.com/blazor-tips-n-tricks-auto-increment-your-version-tag-with-powershell/) Pourquoi versionner ? La version d’une app sert tout simplement de référenciel. De quoi on parle ? De la version 1.12.665 ou ya un bug qui est corrigé dans la V1.13.005. C’est quand même plus pratique.  Le product owner sera aussi attentif à ces versions concernant l’ajout de nouvelles fonctionalités et communiquer dessus.  Ca permet de prévoir une roadmap large et dire par exemple, cette fonctionalité sera attendu pour la V2.3, pas avant.  En parlant de roadmap, je cite souvent Star Citizen qui est un jeux vidéo en béta depuis des années, et qui affiche ses avancés https://robertsspaceindustries.com/roadmap/release-view Il fixe des objectifs par trimestres sous forme de version avec une majeure et une mineure. C’est clair. Mais bon il sort quand ce jeu !!!! C’est une alpha. Et certain ajoute ce terme dans la version.  Alpha, Beta, Rc (Release Candidate), Nightly Build… On peut préciser le contexte de la version.  Versionner une app .net Core avec une Pipeline automatique Tout l’enjeu de cet article. Comment je peux modifier ma pipeline pour inclure un nouveau numéro de build par exemple à ma version et l’afficher en prod. (comme sur Firefox dans la rubrique aide ou a propos) ? Afficher la version dans l’app Pour que l’on voit directement la version dans mon app Blazor, je vais carrément l’afficher en haut a droite : Une page about avec ce numéro aurait été plus propre sur une vraie App. L’idée ici c’est de l’avoir en permanence sous les yeux.  Pour cela on va modifier MainLayout.razor comme ceci La ligne importante est celle ci : Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion; La version par défaut qui s’affiche est 1.0.0. Si vous faites (sous Visual Studio) un clic droit sur le projet client de Blazor, puis propriété et enfin dans la section Package vous verrez ce numéro. Par contre il n’est pas modifiable.  Pour le modifier, il suffit de rajouter dans le .csproj une ligne version. Easy. Bingo YAML comment gérer une version Je veux une version sous cette forme yyyy.mm.dd.xx, donc date + un numéro auto incrémenté. On commence par ajouter un compteur à une variable. Ce compteur sera automatiquement incrémenté à chaque execution de la pipeline. revision: $[counter(format(‘{0:dd}’, pipeline.startTime), 1)] Pour s’en assurer, on va afficher la valeur de notre variable : #display value – script: echo $(revision) displayName: ‘revision display’ Executez plusieurs fois votre pipeline et aller voir ce que ça donne. Par exemple chez moi : J’en suis à mon 24ième run. Il me faut aussi une date du jour. pour cela on va aussi utiliser une variable dateToday ainsi qu’une derniere variable  »versionString"  qui va concaténer ces deux dernières. (1 h pour trouver comment faire… le ‘>’ magique). Ce qui donne : dateToday: ‘Will be set dynamically’ revision: $[counter(format(‘{0:dd}’, pipeline.startTime), 1)] versionString: > $(dateToday).$(revision) Il suffit à présent de générer dateToday. On va utiliser un script PowerShell (pompé et adapté sur ce site) #Preparing Build Number – task: PowerShell@2 displayName: ‘Preparing Build Number’ inputs: targetType: ‘inline’ script: | $currentDate = $(Get-Date) $year = $currentDate.Year $month = $currentDate.Month $day = $currentDate.Day Write-Host $currentDate Write-Host $day Write-Host $env:revision Write-Host « ##vso[task.setvariable variable=dateToday]$year.$month.$day » On vérifie les données : #display value – script: echo $(revision) displayName: ‘revision display’ – script: echo $(dateToday) displayName: ‘dateToday display’ – script: echo $(versionString) displayName: ‘versionString display’ Normalement on a ce résulat : 2022.3.21.29, version numéro 29 faite le 3 mars 2022, elle est pas belle la vie ?  Publication avec la version J’ai légérement adapté mon script de publication qui était anciennement ceci : # Publish Blazor Demo Server – script: dotnet publish –configuration $(buildConfiguration) src/BlazorDemo/BlazorDemo/Server/BlazorDemo.Server.csproj displayName: ‘dotnet publish $(buildConfiguration)’ Remplacé par : # Publish Blazor Demo Server – task: DotNetCoreCLI@2 displayName: Publish inputs: command: publish publishWebProjects: false projects: ‘$(projectBlazorWasmServer)’ arguments: ‘–configuration $(buildConfiguration) –output $(build.artifactstagingdirectory) /p:Version=$(versionString)’ zipAfterPublish: false modifyOutputPath: false…

Azure Devops Pipeline (CI/CD) – Secrets

Cet article concerne le secret de certaine informations, comme un mot de passe, un clé privée etc.  Dutant mon apprentissage sur azure devops, je suis passé par cette étape. Cependant je ne me suis pas servi précisément de ces varibles/files secrets au final car j’ai utilisé le "service connexions" . Néanmoins je trouve cela instrucif, alors je partage. YAML – sécurité Vous avez remarqué, je ne vous ai pas communiqué ma passphrase ni ma clé privée. Sinon vous auriez accès a mon serveur. Ma clé est sur mon poste de dev. La passphrase lisible dans mes scripts d’upload automatique. C’est pas ouf question sécu. Mais vu que je bosse tout seul dessus… ça va, ça passe.  Qu’en est il lorsque l’on travaille à plusieurs dev, avec des sys admins, du cloisement et un niveau de sécurité qui nécessite de pas trop déconner ? Il faut trouver un moyen de sécuriser ces données. Azure Devops utilise des "secure files" et des "secure variables" pour faire cela.  https://docs.microsoft.com/en-us/azure/devops/pipelines/library/secure-files?view=azure-devops Ces données sont HORS repo git. Ainsi personne n’y aura accès en dehors de vous et des autorisations que vous leurs donnerez sur Azure Devops. Par contre elles seront stockées sur Azure Devops… les américains, la CIA, la NSA tout ça tout ça…   Commençons par enregistrer notre passphrase et lui donner la permission pour la pipeline du projet Azure Devops "Blazor Sandbox". Pour cela on va créer une nouveau groupe de variables que j’ai nommé IKoulaGroup. Il faut aller dans Pipelines/Library et cliquer sur Variable group.  Ajouter une variable, donner lui un nom (ex MyPassPhraseIkoula) et une valeur (dans l’exemple Bangali) Notez qu’à droite de la valeur d’une variable se trouve un petit bouton cadena qui permet de masquer celle ci. On y reviendra. Retour sur le YAML Maintenant que l’on a notre variable stockée sur Azure Devops on va pouvoir la récupérer dans notre pipeline Voici comment : On a une première variable qui était déjà là, celle qui concerne le type de build ‘Release’. Elle a un nom et une valeur. Celle ci ne concerne que la pipeline et ne sera vu que de l’agent qui s’occupe de cette pipeline.  Ensuite on a la déclaration du groupe IkoulaGroup qui contient une variable dont le nom est "MyPassPhrase" avec une valeur. Plus d’info sur la doc officielle ici. Plus loin on affiche ces variables avec un echo. Deux façons de récupérer notre variable MyPassPhrase.  tout simplement en l’appellant par $(MyPassPhrase) en utilisant une « expression de runtime » avec $[variables.MyPassPhraseIkoula]. Je pige pas trop ce truc, mais je pose ça la des fois que ça serve plus tard.  Concrètement, je n’arrive pas à récupérer la variable avec cette deuxième technique. Par contre j’ai bien ma variable avec la première façon :On a récupéré notre passphrase "Bangali" de tout à l’heure.  Maintenant un mot de passe ou une passphrase c’est pas censé être affiché tel quel. Vous vous souvenez du petit bouton cadena de tout à l’heure, qui se trouve a droite de votre variable dans la library de pipeline, cliquez dessus pour le vérouiller ainsi : penser à sauvegarder et relancer la même pipeline : notez que cette fois ci, le contenu de la variable est masqué par des **** On sait maintenant comment cacher des informations. 

Azure Devops Pipeline (CI/CD) – Deploy

Objectif : déploiement en production Dans la précédente partie on a déployé une pipeline sur Azure DevOps. Celle ci nous permet de lancer une build dès que la branche master de notre repo Blazor Sandbox reçoit un nouveau commit. De cette manière on s’assure que le build fonctionne ou pas. On est prévenu du résultat par email.  Ce qui serait intéressant, c’est de pouvoir la déployer sur un serveur web automatiquement en cas de succès.  Ma config J’ai un serveur VPS chez iKoula pour 4€/mois, avec une debian linux.  Ca tourne plutot bien. Mais bon, j’ai pas beaucoup de traffic 🙂 Donc j’ai un site web https://dev.blazordemo.reactor.fr et https://blazordemo.reactor.fr qui tournent tous les deux sous Nginx. Derrière chez deux services kestrel asp.net core sous .net 6.0. (pour faire bien, il aurait fallut dissocier la prod de mon dev (ou recette, staging). Petit budget… Dans /var/www/blazordemo.reactor.fr et /var/www/dev.blazordemo.reactor.fr j’ai mes publications de site web asp.net core Blazor WASM (le serveur et le client WASM "all in one"). L’idée est de dire à Azure Devops Pipeline, lorsque la branche master reçoit un nouveau commit, tu publies une version du serveur et tu balances le tout via SSH (sftp). Pipeline YAML On est fixé sur les objectifs. Maintenant il faut traduire cela en YAML. Voici un bout de doc : https://docs.microsoft.com/fr-fr/azure/devops/pipelines/tasks/deploy/copy-files-over-ssh?view=azure-devops En premier lieu, je vais reprendre la précédente pipeline et modifier build par publish. La différence est notable pour Blazor Server WASM. (voir mon article) Un petit commit + push et on voit que Azure Devops lance un nouveau job. On attend qu’il termine et passe au vert. Je pense qu’on va procédé ainsi, à taton. Petit pas par petit pas.  Une modif + commit + push + retour du Job.  Point SSH/SFTP Pour accéder à mon serveur en toute sécurité, je me connecte via SSH. Je prends donc la main à distance depuis mon poste windows sur mon serveur debian linux, qq part en France. J’ai un mot de passe et un login. Et roule ma poule.  Mais on peut faire mieux. J’ai ajouté une paire de clé privée/publique et une passphrase. Ainsi, il faut avoir la clé privée + la passphrase pour accéder.  C’est plus sécurisant pour moi. Je laisse l’accès SSH classique pour des opérations plus ponctuelles. J’ai de mon côté une serie de fichier .bat qui lance une commande de publication .net core et des commandes winscp (permet de lancer des commandes SFTP depuis Windows). La connection se fait via cette clé et cette passphrase. Ainsi, je peux en un double clic mettre à jour ma prod/staging/recette/dev depuis mon poste, sans lacher mon mdp. Au lieu de le faire à la main depuis un client sftp. Ca marche ! C’est moins rapide qu’un client sftp (car les fichiers uplodé ne sont pas lancés en parrallele). J’ai deux types de scripts. La totale, qui met a jour toute la publication : et un autre "rapide" qui ne mets a jours que le minimum pour aller vite : et son fichier .bat  Donc l’idée, c’est de faire pareil sous Azure Devops. Yaml On va rajouter une nouvelle tâche dans notre pipeline YAML avec CopyFilesOverSSH 4 éléments sont à renseigner : sshEndPoint : c’est le nom de notre connexion SSH que l’on va configurer plus loin sourceFolder : le chemin relatif de votre publish. L’agent de build va s’occuper de récupérer votre publish au bon endroit. Attention au majuscule et minuscule si l’agent est sur linux !!! targetFolder: le chemin de destination de votre publication sur la machine cible.  cleanTargetFolder : facultatif, mais effacer le contenu de la destination fait pas de mal.  Service Connections Le sshEndpoint de tout à l’heure est à configurer dans les "project settings" dans la section Pieplines/Service Connections  Il reste plus qu’à créer la votre en cliquant sur le bouton new connection Sélectionnez SSH : puis remplissez selon votre config, en uploadant votre clé privée. Attention, celle ci doit être au format .pem. Et voila. C’est tout.  Relancer votre pipeline avec un petit git add commit push.  Normalement vous devriez avoir que du vert !

Azure Devops Pipeline (CI/CD) – First Build

Intro En général, quand on découvre une techno, on fonce direct en dev local et on s’amuse. C’est ce que j’ai fait aussi, mais j’ai pas tardé à mettre en prod. Car par expérience,  mieux vaut avoir les problèmes au début, tant que le projet est pas trop gros ou trop compliqué.  Donc l’idée de ce billet, c’est voir comment on pourrait monter une chaine CI/CD (continious intergration/ continuious deployement) sur un projet blazor de base.  Projet de base Blazor Avec Visual Studio 2022 Community, on créer un projet Blazor WASM, avec Hebergement Asp.net core et PWA : Pour ma part je l’ai nommé BlazorDemo.  Je me suis permis de modifier qu’une seule ligne, dans program.cs du projet server. Je spécifie juste un port pour ma prod. Voir artile https://reactor.fr/net-core-sous-linux-nginx-80-http-443-https-firewall/ Azure DevOps Pipelines Azure Devops, c’est GitHub, Maven, Jenkins et j’en passe tout ça dans une appli web.  Ca nous permet de faire du CI/CD depuis nos propres repos (qu’ils soient sur BitBucket, Azure devops, GitHub, ou autre…) L’idée est de partir sur deux branches git, une master et une develop.  La master sera considéré comme la Prod. La develop comme la branche de travail.  A chaque fois que la branche master recevra un commit, on lancera une "pipeline" qui fera plusieurs actions, comme builder, lancer des tests et deployer.   A l’avenir, la branche master ne pourra plus recevoir de commit directement, ceci sera bloqué par defaut. Le seul moyen sera de faire une Pull Request depuis la branche develop vers la branche master. Ceci afin de mettre en place de bonne pratique de développement et de gestion de code source.  Bien sûr on pourrait pousser le concept plus loin, en pratiquant du Git Flow par exemple. Mais restons simple pour bien comprendre les mécanismes d’AzureDevOps 1ere pipeline Commençons par créer notre première pipeline. Menu Pipeline Cliquez sur New Pipeline Comme je le disais tout à l’heure, notre code source peut se situer sur différent repos, choisissez le votre : On choisit ensuite son repos, dans mon cas ceci :  Ensuite il faut choisir un modèle de script YAML. Alors ici, c’est pas clair je trouve. J’ai choisis "Asp.net Core" qui n’est pas présenté comme premier choix. Ce qui pourrait m’induire en erreur. Enfin de toute manière, c’est qu’un modèle, qu’on peut modifier par la suite. Voici le résultat : En cliquant sur Save and Run, puis valider l’écran suivant par defaut, vous allez ajouter un fichier "azure-pipelines.yml" a la racine de votre repo, sur la branche master. S’en suit un run automatique, qui au bout de qq seconde va échouer : En cliquant dessus pour voir le détail : Puis sur Job et sur l’élément en rouge : On a le détail du pourquoi le job a échoué. On a le détail du pourquoi le job a échoué. Ca nous dit que l’on a pas spécifier de projet à compiler… et c’est vrai MSBUILD : error MSB1003: Specify a project or solution file. The current working directory does not contain a project or solution file. Correctif de la 1ere pipeline Vous pouvez corriger directement depuis la plateforme azure devops pour bien le faire depuis votre editeur préféré et jouer qq commande git. Pour ma part je préfère cette derniere.  Je récupère donc via un git pull ma branche master sur mon visual studio code et je modifie le fichier azure-pipelines.yml avec cette ligne script: dotnet build –configuration $(buildConfiguration) src/BlazorDemo/BlazorDemo/Server/BlazorDemo.Server.csproj Le path ici peut différer selon votre répertoire repos. (moi j’ai mis tout ca dans un folder src, qui contient un répertoire  blazordemo qui contient un répertoire "solution" blazordemo. Quand votre modification est faites, il faut alors mettre a jour le repo distant avec un commit.  Rappelons que lorsque la branche master subit un nouveau commit, ca lance automatiquement cette pipeline. Et normalement vous obtenez un build vert :  Et voila, on a fait notre première pipelines qui fait qq chose de très basique pour le moment, builder !

Blazor .net 6.0 – décollage

Découverte de Blazor J’ai été très très emballé lorsque j’en ai entendu parlé pour la premiière fois de Blazor. Bien que j’attendais à ce qu’il soit tué dans l’oeuf. Car au début, c’était un side project Microsoft sans prétention. Quelle idée, faire du web avec du C# ? et pourquoi pas VbScript tant qu’on y est… 🙂 Nan mais sans déconner, le js ça va deux minutes. Donc faire une web app en C# je signe.  J’ai donc taté du blazor en mode tuto au début. Puis j’ai oublié. Et me revoila ! Je vais présenter ici mes découvertes. En fait j’ai fait des erreurs et je voulais les écrires pour que qq évite de galérer comme moi.  Blazor .net 6.0 Bon la ça déconne plus. Blazor est officiellement inclu dans .net (depuis .net Core 3.1 il me semble) et donc on peut code pour de vrai, pour de vrai client. Et la ça change tout. Fini les tutos. Alors on  commence avec un nouveau projet sous VS2022. Et celui ci nous propose deux solutions :  Blazor WebAssembly  Balzor Server Blazor Server Ce type de projet est n’y plus n’y moins qu’un projet ASP.net Core avec du Razor en couche de présentation. Si auparavent vous avez fait du web.form pour les plus vieux, du MVC5 ou de l’Asp.net Core vous allez pas être trop perdu.  Pour les autres, on est sur une application classique de type Client (browser) Server (IIS, Apache, Nginx, Kernel…) En ajoutant une couche SignalR vous avez un site web qui déboite. Mais qui ne gère pas le offline. Blazor WebAssembly Le vrai plus est la pour moi. On peut envisager de faire une application web PWA avec .net. Et ça pour un dev Microsoft de 20 ans, c’est juste de la bombe pour moi. Et qui plus est, qui peut tourner sur un OS Linux. (voir articles sur les coûts) Donc Blazor Wasm pour les intimes et une tuerie. On va pouvoir utiliser la puissance du language C#, les outils VS et VS Code, et toutes les libs qu’on a l’habitude d’utiliser depuis des années.  Je vais parler dans le reste de l’article que de Blazor Wasm.      Comment ça marche ? L’objectif de l’article est de vous amener à bien comprendre comment Balzor fonctionne. D’un point de vue architecture applicative et d’un point de vue réseau/serveur.  Lorsque l’on créer un nouveau projet, VS2022 nous demande si on souhaite héberger le site via Asp.net Core. (kernel) Il nous demande aussi si l’on souhaite utiliser des fonctionnalités PWA. Pour ma part oui pour les deux.  Voici la différence entre un projet WASM sans serveur (à droite) et un projet avec : Le projet BlazorApp1.Client et BlazorApp2 (sans server) constituent l’application web PWA. On y trouve du code C#. Mais au final on aura que du code html/css/js pure en sortie et un dossier _framework, qui lui par contre contient qq dll indispensable au bon fonctionnement de blazor.  Voici une publication : On a un webconfig et un repertoire wwwroot qui contient ceci:     C’est la que ca devient chelou. Si on se place coté browser, et surtout en mode déconnecté, on a pas besoin d’un serveur (web, pure static de fichier), (sauf bien entendu lors du premier chargement). Ensuite on peut très bien s’en passer de ce serveur. D’ailleurs pourquoi pas héberger ce client sur un CDN (content delivery Network) Mais alors on a quoi si on se place coté serveur ? Bonne question. C’est la que l’hôte Asp.net Core intervient.  Comme on peut le voir dans le premier projet, on a un projet Server et un projet Shared. Shared est juste un projet de classe, rien de méchant on partage du code commun avec les deux autres projets.  Le projet Server par contre est le code qui va gérer la partie serveur, comme son nom l’indique. Et lui aura aussi la partie cliente. Regarder les sorties d’une publication du projet serveur :  On retrouve bien wwwroot de la partie cliente ! Ceux sont ces fichiers static que le serveur va gérer par la suite avec le browser. Donc pour résumer : On a un projet Blazor Server : projet classique client/serveur (rendu server sur chaque page) avec une liaison SignalR.  On a un projet Blazor WASM : projet PWA (client web autonome) qui peut avoir des options d’hébergement avec l’ajout d’un projet Server + Share. J’avoue qu’on s’y perds avec le terme « Server ». A mon avis les équipes de microsoft on du aussi gamberger pas mal sur le naming. Mais en fait, quand on sait, c’est clair. (complètement conne cette phrase…)   Mes erreurs Sotrie de build Lorsque l’on travaille en debug local, on ne fait pas trop attention à tout cela. Mais dès lors qu’on passe en prod c’est plus la même histoire.  La ou j’ai merdé, c’est de considérer le dossier bin/Release comme ma sortie pour la prod. Erreur ! Allez y faire un tour, on a uniquement la génération du projet courant. Ce qui est logique. Mais la petite nouveauté c’est la publication qui intègre le projet Client dans la sortie du projet Server.  Autre erreur, les ports.  En local on peut configurer les ports des projets Client et Server via le fichier properties/launchSettings.json.Et on peut executer les deux projets. Modifier les ports de ces fichiers et lancer un run.  Mais dans tous les cas ceux qui comptent pour la prod sont ceux du projet serveur. Et moi comme un con, j’avais le projet Client comme projet de démarrage. A éviter car j’ai perdu beaucoup de temps à rien comprendre.  Voila, j’y ai passé presque deux jours (config Ngix sur linux). Donc je résume un peu. Je me disais que ca valait bien un billet. ++

.net Core sous Linux Nginx 80 http 443 https firewall

En voila un titre bien déguelasse. Suite à l’article précédent (comment heberger asp.net, un bref historique) je voulais consigner ici mes trouvailles concernant la mise en place d’un site web asp.net core sur Linux Debian.  Pour cela j’ai loué un VPS Linux chez iKoula pour 4€.  On a donc un accès SSH suite à l’obtention de ce dernier, on se connecte et je vous montre comment on fait un site web qui marche en .net Core.   Sources Voici les quelques sites web qui m’ont servit dans cet article. # Installer Dotnethttps://docs.microsoft.com/fr-fr/dotnet/core/install/linux-debian# Installer un firewall UFWhttps://debian-facile.org/doc:systeme:ufw# Installer NGinxhttps://idroot.us/install-nginx-debian-11/https://www.howtoforge.com/how-to-install-nginx-on-debian-11/# Config Nginxhttps://docs.microsoft.com/fr-fr/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-6.0# Multi Sitehttps://webdock.io/en/docs/how-guides/shared-hosting-multiple-websites/how-configure-nginx-to-serve-multiple-websites-single-vps Projet web Asp.net core On commence par la création locale d’un site web en asp.net core .net 5. Qu’il faut bien entendu avoir sur son poste. Je vous renvois à la doc pour toute la paprasse,  https://docs.microsoft.com/fr-fr/aspnet/core/getting-started/?view=aspnetcore-6.0&tabs=windows C’est une des meilleurs doc du web, donc profitez en. Je vais pas la réinventer, je vais a l’essentiel. La commande suivante va vous créer une api web de base.  dotnet new webapi -o TodoApi On va garder l’exemple de microsoft « TodoApi », qui est en fait une api toute conne avec un seul control qui donne la météo. Je m’en fou total de ce truc, c’est pour l’exemple.  Pour moi il manque une route, celle de la « home ». Alors je rajoute un controler « home Histoire d’avoir qq chose à afficher à la racine du site. On teste le site web  dotnet run.  De base vos ports sont 5001 sur https (avec un certificat local de developer) et 5000 en http.  Ces ports sont localisés dans  Properties/launchSettings.json dans la propriété applicationUrl Si comme moi, vous avez plusieurs sites asp.net core, vous allez probablement changer ces ports. Et on va le voir par la suite cela a une grande importance. Moi je le fait directement dans le code source, mais ya d’autre méthodes. Le site tourne on va le publier  avec la commande suivante  dotnet publish -c Release Ce qui va créer un nouveau répertoire  binReleasenet5.0publish Ou on aura tous les fichiers nécessaires pour notre site web en production dedans.  Install Server VPS Alors avant toute chose, je suis pas un expert linux. Si je dis une connerie, faut le signaler dans les commentaires svp. J’ai un passif Windows qui m’a éloignié de Linux, meme si de base, je suis ingé système et réseau, de ya 20 ans… On commence, on se connecte en SSH.  Alors perso, j’ai découvert une extension de visual studio code qui facilite la vie. C’est Remote-SSH.Ca permet d’éditer des fichiers distants directement dans VS (et d’avoir tous les outils, couleurs, syntaxe, etc…) Mais ca fait aussi explorateur de fichier, FTP et bien entendu on a toujours une ligne de commande à porté de main, tout ca dans VS code. Un must have. Dotnet 5.0 Alors le serveur est une version Debian 11 de linux. C’est important de checker avant si .net Core est compatible ou pashttps://docs.microsoft.com/fr-fr/dotnet/core/install/linux   Nous on continue sur une Debian 11 :https://docs.microsoft.com/fr-fr/dotnet/core/install/linux-debian   On référence les packages Microsoft(wgt ==> w g e t, va savoir pourquoi je peux pas écrire ce mot la sur wordpress) wgt https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb -O packages-microsoft-prod.debsudo dpkg -i packages-microsoft-prod.debrm packages-microsoft-prod.deb   Puis on install le SDK .Net 5.0 (la version 6.0 est sortie peu de temps avant cet article, donc passer en 6.0 c’est mieux)   sudo apt-get updatesudo apt-get install -y apt-transport-httpssudo apt-get updatesudo apt-get install -y dotnet-sdk-5.0 Nginx Pré install  sudo apt update sudo apt upgrade sudo apt install curl gnupg2 ca-certificates lsb-release Install sudo apt install nginx On Check nginx -v Ce qui donne pour moi : nginx version: nginx/1.18.0  on en profite pour installer un firewall ufw apt-get update && apt-get install ufw et on l’active  ufw enable Alors attention, ca pourrait couper votre connexion SSH, mais les gars ils sont pas trop con, ils ont par defaut ouvert le port 22.  On ajoute les règles de bases NGinx sudo ufw allow ‘Nginx HTTP’ A ce stade on devrait avoir un site web qui tourne. Donc aller changer votre DNS pour modifier ou ajouter un domain, par exemple prout.com qui pointe vers l’ip de votre serveur. Profitez en pour ajouter une nouvelle entrée A dans votre zone DNS todoapi.prout.com qui pointe vers la meme IP. Ca peut prendre jusqu’à 24h, mais aujourd’hui ca va plus vite. Si c’est un .fr ca devrait pas trainer. Sinon, faut pinger l’adresse jusqu’à avoir une réponse et une IP qui va bien.  Aller dans votre navigateur préféré et taper votre domaine, pour moi : http://prout.com et si vous voulez pas attendre taper directement l’ip de votre serveur. Notez que pour le moment on parle pas encore de https.  Et bimm : Tu n’as un beau serveur d’enculé ! Config Nginx On fait un pti point pour comprendre les choses.  Dans /var/www/html on a le code source de notre site web.  Dans /etc/Nginx on a notre serveur web Nginx et ses conf Le répertoire sites-available va contenir les configurations de nos sites web. Le répertoire sites-enabled va contenir des liens vers les config précédentes. Ce qui les rendra actives ! C’est ce que l’on va faire, on va créer un nouveau site. Pour cela on va commencer par mettre un nouveau répertoire dans /var/www qui va contenir le publish de tout à l’heure. Alors on y va, on copie… Ensuite il faut créer un fichier dans /etc/nginx/sites-available/, par exemple todoapi.prout.com.conf et on y met ceci server {    server_name todoapi.prout.com;    root /var/www/todapi;    location / {        proxy_pass         http://127.0.0.1:5002;        proxy_http_version 1.1;        proxy_set_header   Upgrade $http_upgrade;        proxy_set_header   Connection keep-alive;        proxy_set_header   Host $host;        proxy_cache_bypass $http_upgrade;        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;        proxy_set_header   X-Forwarded-Proto $scheme;    }  }   Noter 3 points, le serveur name avec le DNS de tout à l’heure. le root avec l’emplacement de notre publish. Et enfin le proxy pass et son port 5002. On…