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
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
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
| Route | Comportement | Ré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/All | Renvoyer les utilisateurs de la liste sous forme de UserPublic. | 200, avec [] si la liste est vide. |
POST /api/User/Register | Recevoir 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/Login | Recevoir 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 :
- Appelez
All: la réponse doit être200avec une liste vide[]. - Inscrivez Alice avec
Register: vérifiez le code200, l’identifiant attribué, le rôle0et l’absence du mot de passe dans la réponse. - Appelez
GET /api/User/{id}avec cet identifiant, puisAll: Alice doit apparaître dans les deux réponses. - Appelez
Loginavec les mêmes identifiants : vous devez recevoir200et les informations publiques d’Alice. Avec un mauvais mot de passe, vous devez recevoir401. - Demandez un identifiant inexistant : vous devez recevoir
404. - 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.slnxcontenant le projetGameServerApi, qui compile sans erreur. - Une API accessible sur le port choisi et une interface Scalar fonctionnelle.
- Les modèles
User,UserInfo,UserPublicet une énumération pour les rôles. - Les quatre routes de
UserControllertestées dans Scalar, avec une listestaticpartagé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.