Module : Programmation .Net C#
Niveau : 4ème Génie Informatique (Spécialité Data Science)
Prérequis : TP 4 validé (Architecture en couches)
Dans le TP 4, vous avez franchi une étape majeure : vous avez sorti le code métier de la vue Razor. Vous êtes passés d'un code "brouillon" à une architecture découplée. Ce chapitre formalise ces concepts : pourquoi séparer les responsabilités ? Comment fonctionne l'injection de dépendances ? Qu'est-ce que l'asynchronisme ?
Le principe de base est la Separation of Concerns (Séparation des préoccupations). Une application moderne ne doit jamais mélanger :
.razor, HTML/CSS).
C'est la couche de présentation.Services/).
Models/).
Pourquoi ? Pour la maintenabilité. Si vous changez le design (HTML), vous ne devriez pas risquer de casser le calcul de la TVA.
Dans le TP, nous avons créé une interface ISensorService. Une interface est un
contrat. Elle définit ce que le service doit faire, mais pas
comment.
public interface ISensorService
{
// Contrat : "Je promets de pouvoir fournir une liste de capteurs"
List<SensorData> GetSensors();
}
Imaginez que vous vouliez tester votre application sans base de données, ou changer de fournisseur de données :
FakeSensorService renvoie une liste en dur
(comme dans le TP).SqlSensorService se connecte à SQL
Server.ApiSensorService appelle une API REST
externe.
Grâce à l'interface, votre page MyDashboard.razor n'a pas besoin de changer. Elle ne
connaît que
le contrat ISensorService.
C'est le cœur d'ASP.NET Core. C'est un mécanisme où les objets ne créent pas leurs
dépendances (avec
new), mais les reçoivent.
Au lieu que MyDashboard crée un new SensorService(),
il dit au système : "J'ai
besoin d'un ISensorService". Le système (le Conteneur IoC) lui en fournit un.
Figure 1 : Flux linéaire de l'Injection de Dépendances
Quand on enregistre un service dans Program.cs, on doit choisir sa durée de vie. C'est
crucial
pour la gestion de la mémoire.
Figure 2 : Visualisation des Cycles de Vie
| Mode | Comportement | Usage typique |
|---|---|---|
| Transient | Une nouvelle instance est créée à chaque fois qu'on la demande. | Services légers sans état (calculs simples). |
| Scoped | Une instance unique créée par connexion utilisateur (Blazor) ou par requête HTTP (API). | Services avec état utilisateur (Panier, Auth, DbContext). Le standard pour Blazor. |
| Singleton | Une instance unique créée au démarrage et partagée par TOUS les utilisateurs. | Cache global, Configuration, Service de logging. |
L'interface utilisateur (la Vue) tourne sur un "Thread principal". Si vous lancez une tâche longue (ex: charger des données pendant 5 secondes) sur ce thread, l'application fige.
Imaginez un serveur dans un restaurant :
- Synchrone (Bloquant) : Le serveur prend votre commande, va en cuisine, et attend devant le cuisinier les bras croisés pendant 20 minutes que le plat soit prêt. Il ne sert personne d'autre. Tout le restaurant est bloqué.
- Asynchrone (Non-Bloquant) : Le serveur donne le bon en cuisine et repart immédiatement servir d'autres clients. Quand la cuisine sonne ("Ding!"), il revient chercher le plat.
En C#, le mot-clé
awaitest le moment où le serveur repart faire autre chose en attendant la réponse de la base de données.
Task : Représente une opération en cours (une "promesse"
de résultat futur).async : Active les fonctionnalités asynchrones dans une
méthode.await : "Mets cette méthode en pause ici, libère le
thread, et reviens quand c'est fini".
// Code Synchrone (Bloquant)
public List<Data> GetData()
{
Thread.Sleep(5000); // L'écran gèle 5 secondes
return data;
}
// Code Asynchrone (Fluide)
public async Task<List<Data>> GetDataAsync()
{
await Task.Delay(5000); // L'écran reste réactif
return data;
}
Singleton pour des
données
utilisateur !async/await pour les opérations
I/O (Bases
de données, Fichiers, API).
Module: .Net C# Programming
Level: 4th Year Computer Engineering (Data Science Specialty)
Prerequisite: LAB 4 Validated (Layered Architecture)
In LAB 4, you achieved a major milestone: you moved business logic out of the Razor view. You transitioned from "messy" code to a decoupled architecture. This chapter formalizes these concepts: Why separate concerns? How does dependency injection work? What is asynchrony?
The core principle is Separation of Concerns. A modern application should never mix:
.razor files, HTML/CSS). This is the
Presentation Layer.Services/ files).Models/ files).Why? For maintainability. If you change the design (HTML), you shouldn't risk breaking the VAT calculation.
In the LAB, we created an ISensorService interface. An interface is a contract.
It defines what the service must do, but not how.
public interface ISensorService
{
// Contract: "I promise I can provide a list of sensors"
List<SensorData> GetSensors();
}
Imagine you want to test your app without a database, or switch data providers:
FakeSensorService returns a hardcoded list (like
in the LAB).SqlSensorService connects to SQL Server.ApiSensorService calls an external REST API.Thanks to the interface, your MyDashboard.razor page doesn't need to change. It only knows the
contract ISensorService.
This is the heart of ASP.NET Core. It's a mechanism where objects don't create their dependencies (with
new), but receive them.
Instead of MyDashboard creating a new SensorService(), it
tells the system: "I need
an ISensorService". The system (the IoC Container) provides one.
Figure 1: Linear Dependency Injection Flow
When registering a service in Program.cs, we must choose its lifetime. This is critical for
memory management.
Figure 2: Lifetime Cycles
| Mode | Description | Typical Usage |
|---|---|---|
| Transient | A new instance is created every time it is requested. | Lightweight, stateless services. |
| Scoped | Unique instance created per user connection (Blazor Server) or per HTTP request (API). | User-state services (Cart, Auth, DbContext). Standard for Blazor. |
| Singleton | Unique instance created at startup and shared by ALL users. | Global cache, Configuration, Logging. |
The User Interface (UI) runs on a "Main Thread". If you run a long task (e.g., loading data for 5 seconds) on this thread, the app freezes.
Imagine a waiter in a restaurant:
- Synchronous (Blocking): The waiter takes your order, goes to the kitchen, and waits in front of the chef with arms crossed for 20 minutes until the dish is ready. Meanwhile, other customers wait. This is inefficient.
- Asynchronous (Non-Blocking): The waiter gives the ticket to the kitchen and immediately goes back to serve other customers. When the kitchen bell rings ("Ding!"), he comes back for the dish.
In C#, the keyword
awaitis the moment the waiter goes to do something else while waiting for the database response.
Task: Represents an ongoing operation (a "promise" of a future
result).async: Enables async features in a method.await: "Pause this method here, free up the thread, and come back
when finished".// Synchronous (Blocking)
public List<Data> GetData()
{
Thread.Sleep(5000); // Screen freezes for 5 seconds
return data;
}
// Asynchronous (Smooth)
public async Task<List<Data>> GetDataAsync()
{
await Task.Delay(5000); // Screen remains responsive
return data;
}
Singleton for user data!async/await for I/O operations
(Databases, Files,
APIs).