Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Semaine 1

Initialisation

Avant de commencer, suivez les instructions d’installation du SDK .NET et de configuration de l’IDE.

Depuis le dossier qui contiendra votre solution, créez une solution .NET nommée IncrementalGame (vous pouvez choisir un autre nom). La commande génère IncrementalGame.slnx, au format XML utilisé par défaut par les SDK .NET récents. Une solution regroupe les projets ; chaque projet possède son propre fichier .csproj.

dotnet new sln -n IncrementalGame

Depuis le même dossier, créez un projet (vous pouvez choisir un autre nom que GameServerApi). Les options de cette commande sont détaillées dans le chapitre Création d’un projet API.

dotnet new webapi --framework net11.0 --use-controllers --no-https -n GameServerApi

Par défaut, Program.cs utilise des instructions de premier niveau : le compilateur génère le point d’entrée. Vous pouvez ajouter l’option --use-program-main à la commande de création si vous préférez une classe Program et une méthode Main explicites. Dans ce cas, placez le code de démarrage des exemples dans Main et les directives using en haut du fichier. Voir le chapitre Main et instructions de premier niveau.

Depuis le dossier de la solution, ajoutez le projet à IncrementalGame.slnx :

dotnet sln add GameServerApi

Si cela a fonctionné vous devriez vous retrouver avec les fichiers suivants dans le dossier GameServerApi:

appsettings.Development.json
appsettings.json
bin/
Controllers/
| WeatherForecastController.cs
obj/
Program.cs
GameServerApi.csproj
GameServerApi.http
Properties/
WeatherForecast.cs

Dotnet CLI

Depuis le dossier de la solution (celui qui contient IncrementalGame.slnx), compilez les projets de la solution :

dotnet build

Pour compiler puis démarrer l’API depuis ce même dossier, indiquez le projet à lancer :

dotnet run --project GameServerApi/

L’option --project indique le chemin du dossier contenant le fichier .csproj. Adaptez ce chemin si vous avez choisi un autre nom de projet.

Pour relancer automatiquement l’application lors des modifications, toujours depuis le dossier de la solution :

dotnet watch --project GameServerApi/

Si votre terminal est déjà dans le dossier du projet GameServerApi, les commandes courtes dotnet build, dotnet run et dotnet watch suffisent. Sans --project, dotnet run et dotnet watch cherchent le projet dans le dossier courant. Arrêtez l’application avec Ctrl+C avant de la relancer.

Fixer le port de l’application

Pour retrouver votre API à la même adresse à chaque lancement, ouvrez GameServerApi/Properties/launchSettings.json. Dans le profil http, définissez applicationUrl sur http://localhost:5000 :

{
  "$schema": "https://json.schemastore.org/launchsettings.json",
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "http://localhost:5000",
      "launchUrl": "scalar/v1",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

applicationUrl fixe l’adresse et le port d’écoute de l’API. launchUrl indique seulement la page à ouvrir dans le navigateur : ici, l’interface Scalar une fois configurée dans la section suivante.

Arrêtez l’application avec Ctrl+C, puis relancez-la depuis le dossier de la solution en sélectionnant le profil http :

dotnet run --project GameServerApi/ --launch-profile http

Vérifiez que le terminal affiche Now listening on: http://localhost:5000. Votre API utilise désormais le port 5000. Si ce port est déjà occupé, choisissez un autre port libre dans applicationUrl, puis redémarrez l’application.

Ce fichier configure le lancement en développement local ; il ne configure pas le port de l’application déployée. Consultez la documentation des profils de lancement pour en savoir plus.

Les paquets .NET avec NuGet

Un paquet est une bibliothèque que vous pouvez ajouter à votre projet pour utiliser des fonctionnalités existantes. .NET utilise le gestionnaire de paquets NuGet ; les paquets publics sont disponibles sur nuget.org.

Pour installer un paquet, exécutez cette commande depuis le dossier contenant le fichier .csproj, en remplaçant NomDuPaquet par son nom :

dotnet add package NomDuPaquet

La commande ajoute une référence au paquet dans le fichier .csproj et télécharge ses dépendances, les autres paquets nécessaires à son fonctionnement. Pour choisir une version précise, ajoutez --version NumeroDeVersion. Après avoir récupéré un projet, dotnet restore télécharge les paquets référencés ; cette restauration est aussi effectuée automatiquement par dotnet build et dotnet run.

Dans la partie suivante, nous allons installer le paquet Scalar.AspNetCore pour ajouter une interface de test à notre API.

Tester l’API avec Scalar

Scalar fournit une interface web pour consulter les routes de votre API et leur envoyer des requêtes. Mettez-le en place dès maintenant pour tester l’API générée, avant de créer votre contrôleur User.

Suivez le chapitre Scalar pour installer le paquet Scalar.AspNetCore, configurer OpenAPI et Scalar dans Program.cs, puis ouvrir automatiquement son interface avec Properties/launchSettings.json. Exécutez la commande d’installation du paquet depuis le dossier GameServerApi, qui contient le fichier .csproj.

Lancez ensuite l’API depuis le dossier de la solution :

dotnet run --project GameServerApi/ --launch-profile http

Ouvrez l’adresse HTTP affichée dans le terminal en ajoutant /scalar/v1 à la fin, http://localhost:5000/scalar/v1 si vous avez conservé le port défini dans la section précédente.

Dans Scalar, ouvrez la route GET du contrôleur WeatherForecast et envoyez une requête. Vérifiez que vous recevez une réponse HTTP 200 contenant des prévisions météo au format JSON. Ce premier test confirme que l’API et son interface de test fonctionnent avant de poursuivre.

Structure

Consultez le chapitre Structure d’un projet Web API pour comprendre le rôle des fichiers et des dossiers générés.

Une fois le projet créé je vous invite a créer un dossier Models dans lequel seront stocké les classes de notre projet.

Vous pouvez dès a présent y déplacer WeatherForecast.cs

Gardez le contrôleur WeatherForecast et sa classe comme exemple jusqu’au premier test réussi de votre contrôleur User. Vous pourrez ensuite les supprimer.

Création d’un Controller

Vous allez désormais pouvoir créer votre propre Controller. Le chapitre Contrôleur explique sa structure et les annotations utilisées pour définir les routes.

Pour cela c’est assez simple il existe une commande dotnet.

Il s’agit de dotnet new apicontroller Elle prend plusieurs paramètres dont:

  • -n : Le nom du controller
  • -p:n : Le namespace du controller
  • -ac : Si vous voulez ajouter des actions CRUD (Create, Read, Update, Delete)
  • -o : Le dossier dans lequel vous voulez créer le controller

Pour créer un controller User dans le dossier Controllers avec des actions CRUD, exécutez la commande suivante depuis le dossier du projet GameServerApi (celui qui contient GameServerApi.csproj). Si vous êtes dans le dossier de la solution, entrez d’abord dans le projet avec cd GameServerApi :

dotnet new apicontroller -n UserController -p:n GameServerApi.Controllers -ac true -o Controllers
Remplacez `GameServerApi` par le nom de votre projet. Celui-ci est le nom que vous avez donné dans la commande `dotnet new webapi`

Si vous connaissez la structure du controller, vous pouvez très bien créer le fichier à la main. Il est aussi possible de copier un controller existant et de le modifier.

Utilisateur

Vous devrez créer une classe Utilisateur dans le dossier Models (Models/User.cs). Pour définir ses données, appuyez-vous sur les chapitres Types des variables et Propriétés.

Un utilisateur sera caractérisé par :

  • Son Id
  • Son pseudo
  • Son mot de passe
  • Son rôle (User, Admin)

Pour le rôle, utilisez une énumération nommée Role, avec les valeurs User = 0 et Admin = 1. Nommez les propriétés Id (int), Pseudo (string), Password (string) et Role (Role).

User Controller

Un endpoint ou une route est une adresse web qui permet d'accéder à une ressource.

Votre premier controller aura pour rôle de gérer les utilisateurs.

Le chapitre Méthodes HTTP rappelle le rôle de GET et de POST. Pour choisir les réponses de vos actions, consultez les Codes de retour d’un contrôleur.

Il devra fournir les endpoints suivants:

GET /api/User/{id} // Renvoi l'utilisateur correspondant à l'id
POST /api/User/Register // Renvoi l'utilisateur dont on demande la création
POST /api/User/Login // Renvoi l'utilisateur
GET /api/User/All // Renvoi une liste d'utilisateurs

Pour les endpoints Register et Login, ils prendront en paramètre une classe UserInfo qui contiendra le pseudo et le mot de passe. La partie Envoyer de la donnée montre comment recevoir un objet dans une action POST. Le controlleur retournera une classe UserPublic quand il devra retourner un utilisateur, cette classe est similaire a User mais sans le mot de passe.

Une fausse base de données en mémoire

Pour cette première semaine, utilisez une liste static dans UserController pour stocker les utilisateurs :

private static readonly List<User> _users = new();

Le mot-clé static signifie que la liste appartient à la classe : toutes les instances de UserController partagent la même liste. Ainsi, un utilisateur ajouté lors d’une requête reste disponible pour les requêtes suivantes. Avec un simple champ d’instance, la liste ne serait pas partagée entre les instances du contrôleur. readonly empêche de remplacer la liste par une autre, mais permet toujours d’y ajouter des utilisateurs.

Consultez le chapitre Collections pour manipuler une List<User>.

La liste est vide au démarrage. Pour attribuer des identifiants, ajoutez un compteur partagé, initialisé à 1 :

private static int _nextId = 1;

Lors de l’inscription, attribuez la valeur de _nextId au nouvel utilisateur, puis incrémentez le compteur. Le rôle attribué par le serveur sera toujours Role.User.

Cette liste simule une base de données : elle reste en mémoire uniquement pendant l’exécution de l’application. Un redémarrage, y compris lors d’un rechargement par dotnet watch, vide la liste et réinitialise le compteur. Nous la remplacerons par une base de données en semaine 2. Pour cet exercice, effectuez les requêtes une par une : la liste et le compteur ne gèrent pas les modifications concurrentes.

Comportement attendu des routes

RouteComportementRéponse HTTP
GET /api/User/{id}Chercher un utilisateur dans la liste par son identifiant et renvoyer un UserPublic.200, ou 404 si aucun utilisateur ne correspond.
GET /api/User/AllRenvoyer les utilisateurs de la liste sous forme de UserPublic.200, avec [] si la liste est vide.
POST /api/User/RegisterRecevoir un UserInfo, créer un User, lui attribuer un identifiant et le rôle User, l’ajouter à la liste et renvoyer un UserPublic.200.
POST /api/User/LoginRecevoir un UserInfo, chercher un utilisateur dont le pseudo et le mot de passe correspondent et renvoyer un UserPublic.200, ou 401 si les identifiants ne correspondent pas.

Exemple de corps JSON pour Register et Login :

{
  "pseudo": "Alice",
  "password": "exemple-fictif"
}

Exemple de réponse après la première inscription :

{
  "id": 1,
  "pseudo": "Alice",
  "role": 0
}

Par défaut, l’énumération est représentée par un nombre dans le JSON : 0 correspond à Role.User. Ne renvoyez jamais directement un User : construisez un UserPublic pour chaque utilisateur retourné, y compris dans la liste de All.

Utilisez uniquement des mots de passe fictifs pour cette simulation. Le hachage des mots de passe sera introduit en semaine 2 ; aucun token JWT n’est demandé cette semaine. La gestion des pseudos en double reste hors du périmètre de cette séance.

Vérification finale et livrables

Une fois votre contrôleur User terminé, relancez l’API et ouvrez Scalar. Vérifiez que ses quatre routes apparaissent, puis réalisez le scénario suivant sans redémarrer l’application entre les requêtes :

  1. Appelez All : la réponse doit être 200 avec une liste vide [].
  2. Inscrivez Alice avec Register : vérifiez le code 200, l’identifiant attribué, le rôle 0 et l’absence du mot de passe dans la réponse.
  3. Appelez GET /api/User/{id} avec cet identifiant, puis All : Alice doit apparaître dans les deux réponses.
  4. Appelez Login avec les mêmes identifiants : vous devez recevoir 200 et les informations publiques d’Alice. Avec un mauvais mot de passe, vous devez recevoir 401.
  5. Demandez un identifiant inexistant : vous devez recevoir 404.
  6. Redémarrez l’application, puis appelez All : la liste doit être à nouveau vide.

À la fin de la séance, vous devez avoir :

  • Une solution IncrementalGame.slnx contenant le projet GameServerApi, qui compile sans erreur.
  • Une API accessible sur le port choisi et une interface Scalar fonctionnelle.
  • Les modèles User, UserInfo, UserPublic et une énumération pour les rôles.
  • Les quatre routes de UserController testées dans Scalar, avec une liste static partagée comme fausse base de données et aucun mot de passe retourné.

Conservez un exemple de requête et de réponse pour chaque route, avec le code HTTP obtenu. Vous devez pouvoir expliquer le chemin d’une requête : méthode et URL, action du contrôleur appelée, données reçues et réponse renvoyée.