Accueil › Les fondations › Chapitre 1

C'est quoi .NET ?

Avant de parler de code, il faut savoir où on met les pieds. Ce chapitre installe le décor : qui exécute ton programme, qui le traduit, qui nettoie derrière lui, et pourquoi il existe autant de numéros de version.

En une phrase

.NET est une plateforme : un moteur qui exécute des programmes, une immense bibliothèque de code déjà écrit, et des outils pour fabriquer tout ça. C# est un langage qu'on utilise pour écrire ces programmes. Les deux sont différents, comme la route et la voiture.

L'image

.NET, c'est une cuisine professionnelle livrée clé en main.

Les cinq noms qu'on confond tout le temps

NomC'est quoiAnalogie
C#Le langage de programmation. Une syntaxe, des mots-clés.Le français
.NETLa plateforme : moteur d'exécution + bibliothèques + outils. Aujourd'hui en version 10.Le pays avec ses routes et ses magasins
ASP.NET CoreLa partie de .NET dédiée au web : serveur HTTP, API, sites, Blazor.Le quartier des affaires
EF CoreLa bibliothèque qui parle aux bases de données.Le traducteur assermenté
.NET Framework historique Attention, faux ami. L'ancienne plateforme (dernière version 4.8), Windows uniquement, encore maintenue mais close : plus aucune nouveauté. « .NET tout court » désigne le successeur multiplateforme. L'ancienne ville, toujours habitée mais plus agrandie
Piège de vocabulaire

Si tu cherches sur internet et que tu tombes sur du code .NET Framework 4.x, une bonne partie peut être obsolète : Global.asax, web.config, HttpContext.Current, System.Web… Ces éléments n'existent plus dans .NET moderne. Ajoute toujours la version dans tes recherches : « asp.net core 10 », pas « asp.net ».

Que se passe-t-il quand tu appuies sur « Exécuter » ?

Ton fichier .cs est un fichier texte. Le processeur ne comprend pas le texte. Il faut donc traduire — et .NET le fait en deux temps, ce qui est la clé pour comprendre beaucoup de comportements.

Program.cs ton texte Roslyn compilateur C# dotnet build MonApp.dll code IL (pas encore machine) CLR le runtime : charge, JIT-compile, exécute, nettoie la mémoire 01001010 → processeur ① Compilation (une fois, à la fabrication) ② Traduction finale + exécution (à chaque lancement, sur la machine cible)
Deux traductions : C# → IL à la compilation, puis IL → instructions machine par le JIT au moment d'exécuter.

Pourquoi deux étapes plutôt qu'une ?

Sous le capot : la compilation par paliers

Le JIT ne compile pas tout de la même façon. Au démarrage il utilise le palier 0 : compilation très rapide, code médiocre. Une méthode appelée plus de 30 fois environ est promue au palier 1 : recompilation optimisée, avec parfois de la guarded devirtualization (le JIT parie sur le type réel observé et garde un test de sécurité). C'est pourquoi un premier appel est lent, et pourquoi mesurer une performance sans phase d'échauffement ne veut rien dire — voir le chapitre 19.

À cela s'ajoute ReadyToRun (R2R) : du code machine pré-généré embarqué dans la DLL en plus de l'IL, pour éviter le coût du palier 0 au démarrage. Le framework lui-même est livré ainsi.

Et l'AOT, alors ?

Avec Native AOT (<PublishAot>true</PublishAot>), tout est compilé en langage machine avant livraison : plus de JIT, plus d'IL à l'exécution. On gagne un démarrage en quelques millisecondes et une empreinte mémoire réduite — précieux pour les conteneurs, les fonctions serverless et les CLI. On perd la réflexion dynamique, Assembly.Load, l'émission de code à la volée, et donc certaines bibliothèques. C'est un choix de fin de projet, pas de début.

SDK ou runtime : lequel installer ?

SDK — pour développer

Contient le compilateur, les modèles de projet, la commande dotnet… et un runtime. C'est ce que tu installes sur ta machine.

dotnet --list-sdks
dotnet new webapi -o MonApi
dotnet run
Runtime — pour exécuter seulement

Le strict nécessaire pour faire tourner une application déjà compilée. C'est ce qu'on installe sur un serveur… ou rien du tout, si tu publies l'application avec son runtime embarqué (self-contained, voir chapitre 20).

dotnet --list-runtimes
Bon réflexe

Plusieurs SDK peuvent cohabiter sans conflit. Pour épingler une version précise sur un projet (utile en équipe et en intégration continue), ajoute un fichier global.json à la racine :

{ "sdk": { "version": "10.0.100", "rollForward": "latestFeature" } }

La mémoire, gérée pour toi

En C, le développeur réserve et libère la mémoire à la main. En .NET, le ramasse-miettes s'en charge : dès qu'un objet n'est plus accessible par personne, sa place est récupérée. Tu ne libères rien, tu ne comptes rien.

① Tu crées des objets cmd ligne tmp log ② Certains ne sont plus référencés cmd ligne tmp log rouge = personne ne les tient ③ Le GC passe et compacte cmd ligne place libérée ♻
Un objet devient « collectable » dès qu'aucune variable vivante ne le désigne. Le GC ne fait pas disparaître les objets utiles.
Sous le capot : générations

Le GC parie sur un constat empirique : la plupart des objets meurent jeunes. Il range donc le tas en générations. Gen 0 est petite et balayée très souvent (quelques microsecondes) ; les survivants passent en Gen 1 puis Gen 2, balayée rarement mais plus coûteuse. Les objets de plus de 85 000 octets vont dans le LOH (Large Object Heap), rarement compacté — d'où l'intérêt de ArrayPool pour les gros tampons. Conséquence pratique : allouer beaucoup de petits objets éphémères coûte peu, mais garder par erreur une référence vers eux (un événement jamais désabonné, un cache statique) les promeut en Gen 2 et crée une fuite mémoire.

Ce que le GC ne fait PAS

Il ne libère que la mémoire .NET. Un fichier ouvert, une connexion réseau, un handle Windows ne sont pas de la mémoire : il faut les fermer explicitement, ce qui est le rôle de IDisposable et du mot-clé using (chapitre 9).

La bibliothèque de base et NuGet

Une part énorme de la valeur de .NET tient à ce qui est déjà écrit. Manipuler des dates, lire un fichier, appeler une API HTTP, trier une liste, parser du JSON : tout est fourni.

Exemples de la bibliothèque de base — rien à installer
using System.Text.Json;                       // JSON
using System.Net.Http.Json;                   // appels HTTP + JSON

var texte = File.ReadAllText("data.txt");                  // fichiers
var demain = DateTime.Today.AddDays(1);                    // dates
var mots = texte.Split(' ', StringSplitOptions.RemoveEmptyEntries);
var json = JsonSerializer.Serialize(new { mots = mots.Length });

using var http = new HttpClient();
var meteo = await http.GetFromJsonAsync<Meteo>("https://api.exemple.fr/meteo");

Quand la bibliothèque de base ne suffit pas, on va chercher un paquet sur NuGet :

dotnet add package Serilog.AspNetCore     # ajoute la dépendance au .csproj
dotnet list package --outdated            # ce qui a une nouvelle version
dotnet list package --vulnerable          # failles de sécurité connues
Bon réflexe avant d'ajouter un paquet

Anatomie d'un projet

Ce que crée dotnet new webapi -o MonApi
MonApi/
├── MonApi.csproj        # la fiche d'identité du projet
├── Program.cs           # le point d'entrée : tout commence ici
├── appsettings.json     # la configuration
├── Properties/
│   └── launchSettings.json   # ports et profils de lancement (dev seulement)
├── bin/                 # résultat de la compilation  → jamais dans Git
└── obj/                 # fichiers temporaires        → jamais dans Git
MonApi.csproj — presque tout est implicite aujourd'hui
<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>   <!-- version de .NET visée -->
    <Nullable>enable</Nullable>                   <!-- alerte sur les null : à garder -->
    <ImplicitUsings>enable</ImplicitUsings>       <!-- using System; etc. automatiques -->
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>  <!-- recommandé -->
  </PropertyGroup>
</Project>

Pas de liste de fichiers : tous les .cs du dossier sont inclus automatiquement. Un projet se compile en un seul assembly (le .dll dans bin/), et cette frontière compte : c'est elle que délimite le mot-clé internal (chapitre 6).

Applications à fichier unique

Depuis .NET 10, un simple fichier .cs peut être exécuté directement, avec ses dépendances déclarées en commentaires spéciaux — pratique pour un script ou une démonstration :

#!/usr/bin/env dotnet
#:package Humanizer@2.14.1

Console.WriteLine(TimeSpan.FromMinutes(90).Humanize());

Exécution : dotnet run script.cs. .NET 11 y ajoute #:include pour découper en plusieurs fichiers, et l'inclusion directe d'une DLL compilée.

Les versions : LTS, STS, et laquelle choisir

Une version de .NET sort chaque année en novembre. Les numéros pairs sont LTS : trois ans de correctifs. Les impairs sont STS : dix-huit mois.

VersionSortieTypeFin de supportC#
.NET 8nov. 2023LTSnov. 202612
.NET 9nov. 2024STSmai 2026 (terminé)13
.NET 10nov. 2025LTSnov. 202814
.NET 11prévu 10 nov. 2026STSvers mai 202815

La règle simple : nouveau projet ou migration → .NET 10. Les versions STS servent à ceux qui mettent à jour en continu et veulent les nouveautés tôt. Monter de version majeure est en général peu coûteux en .NET moderne : changer net8.0 en net10.0, recompiler, lire les breaking changes annoncés.

Les commandes du quotidien

CommandeCe qu'elle fait
dotnet new listListe les modèles de projet disponibles
dotnet new webapi -o ApiCrée une API web dans le dossier Api
dotnet runCompile et lance
dotnet watchRelance (ou applique à chaud) dès qu'un fichier change
dotnet buildCompile seulement
dotnet testExécute les tests
dotnet add package XAjoute une dépendance NuGet
dotnet add reference ../Lib/Lib.csprojFait dépendre un projet d'un autre
dotnet publish -c ReleaseProduit le livrable pour la production
dotnet formatMet en forme le code selon les règles du projet
Le trio à retenir pour démarrer
dotnet new webapi -o MonApi
cd MonApi
dotnet watch

Trois lignes, et tu as une API qui tourne et se recharge quand tu modifies le code.

Vérifie que c'est passé

🎯 Quiz — 4 questions

1. Sur un serveur qui doit seulement exécuter ton application, tu installes…

Le SDK sert à fabriquer. Sur un serveur, le runtime suffit — et une publication self-contained embarque même ce runtime, ce qui n'exige plus rien d'installé.

2. Le fichier MonApp.dll produit par dotnet build contient…

C'est ce double étage qui permet au même fichier de tourner sur Windows, Linux ou ARM. La traduction finale est faite par le JIT, sur la machine cible.

3. Ton application garde en mémoire des objets qui devraient être libérés. Le GC est-il en cause ?

Le GC ne libère pas ce qui est encore accessible. Cherche la référence oubliée : cache statique, événement non désabonné, tâche de fond qui capture un objet. GC.Collect() ne résout rien et dégrade les performances.

4. Nouveau projet d'entreprise démarré aujourd'hui : quelle version ?

.NET Framework ne reçoit plus de nouveautés. Un aperçu n'a pas de support en production. .NET 10 est le choix par défaut jusqu'à la sortie de .NET 12 (fin 2027).

Fiches de révision

Clique pour retourner la carte.

SDK vs runtime ?
SDK = fabriquer (compilateur, modèles, CLI). Runtime = exécuter. Le SDK contient un runtime.
IL, c'est quoi ?
Le code intermédiaire produit par la compilation C#, stocké dans la DLL. Traduit en langage machine par le JIT au lancement.
Que fait le GC ?
Il récupère la mémoire des objets que plus personne ne référence. Il ne ferme pas les fichiers ni les connexions : c'est le rôle de using.
LTS ou STS ?
Pair = LTS = 3 ans (8, 10). Impair = STS = 18 mois (9, 11). En production : LTS.
Un projet produit quoi ?
Un assembly (.dll ou .exe) dans bin/. C'est aussi la frontière du mot-clé internal.
.NET vs .NET Framework ?
.NET (5→11) = moderne, multiplateforme, évolutif. .NET Framework 4.8 = Windows, maintenu mais figé.
À retenir