19 KiB
Analyse de l'API C# SkydiveLogs - Architecture et Fonctionnement
Vue d'ensemble
L'API SkydiveLogs est une application ASP.NET Core MVC développée avec une architecture modulaire propre, divisée en six projets distincts qui reposent sur une architecture en couches (Layered Architecture) :
Structure du Projet
SkydiveLogs/Back/
├── skydiveLogs-api/ # Projet principal (Web API + Point d'entrée)
├── skydiveLogs-api.Domain/ # Modèles de domaine (Entités)
├── skydiveLogs-api.DomainBusiness/ # Couche business logique (Services)
├── skydiveLogs-api.DomainService/ # Couche d'accès aux données (Repositories)
├── skydiveLogs-api.Infrastructure/ # Implémentations des repositories
├── skydiveLogs-api.Ioc/ # Service d'injection de dépendances
└── skydiveLogs-api.sln # Fichier de solution
1. Architecture des Couches
1.1 Architecture Clean/Modulaire
L'API suit le pattern Clean Architecture avec une séparation claire des responsabilités :
┌─────────────────────────────────────────────────────┐
│ skydiveLogs-api (Presentation Layer) │
│ - Controllers │
│ - Program.cs / Startup.cs │
└────────────────┬────────────────────────────────────┘
│
┌────────────────▼────────────────────────────────────┐
│ skydiveLogs-api.Ioc (Dependency Injection) │
│ - Configuration IoC │
└────────────────┬────────────────────────────────────┘
│
┌────────────────▼────────────────────────────────────┐
│ skydiveLogs-api.DomainBusiness (Business Layer) │
│ - Services (Interfaces + Implémentations) │
│ - Logique métier │
└────────────────┬────────────────────────────────────┘
│
┌────────────────▼────────────────────────────────────┐
│ skydiveLogs-api.DomainService (Data Access Layer) │
│ - Repositories (Interfaces) │
└────────────────┬────────────────────────────────────┘
│
┌────────────────▼────────────────────────────────────┐
│ skydiveLogs-api.Infrastructure (Implementation) │
│ - Repositories implémentés │
│ - LiteDbProvider │
└────────────────┬────────────────────────────────────┘
│
┌────────────────▼────────────────────────────────────┐
│ skydiveLogs-api.Domain (Domain Layer) │
│ - Modèles de données (Entities) │
└─────────────────────────────────────────────────────┘
1.2 Injection de Dépendances (IocService)
Le projet skydiveLogs-api.Ioc gère toute l'injection de dépendances via la classe IocService :
Services Injectés
- Aircraft, Gear, DropZone, Jump, JumpType, Tunnel, User et leurs services
- Stats services (analytique)
- CacheService (singleton pour le cache)
- IdentityService (authentification)
- Repositories pour chaque entité
- LiteDbProvider (fournisseur de données LiteDB)
services.AddScoped<IAircraftService, AircraftService>();
services.AddScoped<IGearService, GearService>();
services.AddScoped<IDropZoneService, DropZoneService>();
services.AddScoped<IJumpService, JumpService>();
// ... et ainsi de suite pour tous les services
2. Configuration de l'Application (Startup.cs)
2.1 Configuration de l'Application
Le fichier Startup.cs configure :
-
Authentication JWT
- Validation du token JWT avec :
- Vérification de l'émetteur (issuer)
- Vérification de l'audience (audience)
- Vérification de l'expiration (lifetime)
- Validation de la clé de signature
- Validation du token JWT avec :
-
CORS
- Configuration pour autoriser la communication avec l'application front-end
-
Initialisation de la Base de Données
- Vérification de l'existence du fichier LiteDB
- Appel à
InitDbService.GenerateDb()si le fichier n'existe pas - Appel à
InitDbService.Update()si le fichier existe
2.2 Programme Principal (Program.cs)
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
=> WebHost.CreateDefaultBuilder(args).UseStartup<Startup>();
3. Architecture des Contrôleurs
Tous les contrôleurs héritent de la classe de base Base :
3.1 Classe Base
[Route("api/[controller]")]
[ApiController]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class Base : ControllerBase { }
Annotations importantes :
Route("api/[controller]"): Préfixe "api/" pour toutes les routesApiController: Optimisations pour les APIAuthorize: Requêtes authentifiées via JWT
3.2 Structure Type des Contrôleurs
Chaque contrôleur suit le même pattern :
public class XxxController : Base
{
public XxxController(IxxxService xxxService, IMapper mapper)
{
_xxxService = xxxService;
_mapper = mapper;
}
[HttpGet]
public IEnumerable<XxxResp> Get() { ... }
[HttpGet("{id}")]
public XxxResp Get(int id) { ... }
[HttpPost]
public void Post([FromBody] XxxReq value) { ... }
[HttpPut("{id}")]
public void Put(int id, [FromBody] XxxReq value) { ... }
[HttpDelete("{id}")]
public void Delete(int id) { ... }
}
4. Entités de Domaine (skydiveLogs-api.Domain)
4.1 Entités Principales
Jump (Saut de parachutisme)
public class Jump
{
public Aircraft Aircraft { get; set; }
public int DeployAltitude { get; set; }
public DropZone DropZone { get; set; }
public int ExitAltitude { get; set; }
public Gear Gear { get; set; }
public int Id { get; set; }
public bool IsSpecial { get; set; }
public DateTime JumpDate { get; set; }
public JumpType JumpType { get; set; }
public string Notes { get; set; }
public User User { get; set; }
public bool WithCutaway { get; set; }
}
Autres entités :
- Aircraft : Données des aéronefs
- User : Utilisateurs (avec authentification)
- DropZone : Zones de parachute (parachute drops)
- Gear : Équipement
- JumpType : Types de sauts
- Tunnel : Données de tunnels
- TunnelFlight : Vols de tunnel
- CacheType : Types de cache
User (avec authentification)
public class User
{
public string Email { get; set; }
public string FirstName { get; set; }
public int Id { get; set; }
public bool IsAdmin { get; set; }
public string Language { get; set; }
public string LastName { get; set; }
public string Login { get; set; }
public string Password { get; set; }
}
4.2 Modèles de Statistiques
Des entités dédiées pour les statistiques :
Statistic- Statistiques généralesStatsByAircraft- Statistiques par aéronefStatsByDz- Statistiques par zone de parachuteStatsByGear- Statistiques par équipementStatsByJumpType- Statistiques par type de sautStatsByYear- Statistiques par annéeStatsByYearByJumpType- Statistiques croisées année/typeStatsForLastMonthByDz- Statistiques du dernier moisStatsForLastYearByDz- Statistiques de l'année dernière
5. Services de Business Logic (skydiveLogs-api.DomainBusiness)
5.1 Services Disponibles
Chaque service implémente une interface dans Interfaces :
Services CRUD
AircraftService- Gestion des aéronefsDropZoneService- Gestion des zones de parachuteGearService- Gestion de l'équipementJumpService- Gestion des sauts (principal)JumpTypeService- Gestion des types de sautsTunnelService- Gestion des tunnelsTunnelFlightService- Gestion des vols de tunnelUserImageService- Gestion des images utilisateursUserService- Gestion des utilisateurs
Services de Cache
CacheService- Gestion du cacheIdentityService- Gestion de l'identité/authentification
Services d'Initialisation
InitDbService- Initialisation de la base de données
Services Statistiques
StatsService- Statistiques généralesStatsByAircraftService- Par aéronefStatsByDzService- Par zone de parachuteStatsByGearService- Par équipementStatsByJumpTypeService- Par type de sautStatsByYearService- Par annéeStatsByYearByJumpTypeService- Croisé année/typeStatsForLastMonthByDzService- Dernier moisStatsForLastMonthByJumpTypeService- Dernier moisStatsForLastYearByDzService- Dernière annéeStatsForLastYearByJumpTypeService- Dernière année
5.2 Implémentations de Services (ex: JumpService)
Les services implémentent la logique métier et utilisent les repositories :
public class JumpService : IJumpService
{
private readonly IJumpRepository _jumpRepository;
private readonly IMapper _mapper;
public void AddNewJump(...) { ... }
public void DeleteJumpById(int id) { ... }
public IEnumerable<Jump> GetAllJumps() { ... }
public Jump GetJumpById(int id) { ... }
public Jump GetJumpByUserAndDate(...) { ... }
public int GetJumpCount() { ... }
public IEnumerable<Jump> GetJumpsByIndexes(...) { ... }
public Jump UpdateJump(int id, Jump jump) { ... }
}
6. Répositories (skydiveLogs-api.DomainService et Infrastructure)
6.1 Couche DomainService
Contient uniquement les interfaces IxxxRepository qui définissent le contrat d'accès aux données.
6.2 Couche Infrastructure
Implémente concrètement les repositories avec LiteDB (base de données fichier NoSQL) :
public class JumpRepository : IJumpRepository
{
private readonly IDataProvider _dataProvider;
private readonly IRepository<Jump> _jumpCollection;
// Implémentation concrète
}
LiteDbProvider est utilisé comme fournisseur de données pour l'accès au fichier LiteDB.
7. Gestion des Données (Data)
7.1 Structure du Folder Data
skydiveLogs-api/Data/
├── Aircraft/
├── DropZone/
├── FavoriteDropZone/
├── Gear/
├── Image/
├── Jump/
├── JumpType/
├── StatsByAircraft/
├── StatsByDz/
├── StatsByGear/
├── StatsByJumpType/
├── StatsByYear/
├── StatsByYearByJumpType/
├── StatsForLastMonthByDz/
├── StatsForLastMonthByJumpType/
├── StatsForLastYearByDz/
├── StatsForLastYearByJumpType/
├── Tunnel/
├── TunnelFlight/
└── User/
Chaque dossier correspond à une collection LiteDB.
7.2 Contrats de Données (DataContract)
Les fichiers DataContract contiennent les DTOs (Data Transfer Objects) :
Requête (Req)
AircraftReq,DropZoneReq,GearReq,JumpReq,JumpTypeReqUserReq,TunnelFlightReq,ImageReq
Réponse (Resp)
AircraftResp,AircraftSimpleResp,DropZoneResp,DropZoneSimpleRespGearResp,JumpResp,JumpListResp,JumpTypeRespUserResp,TunnelResp,TunnelFlightResp,ImageRespStatisticResp,StatisticForChartRespSimpleSummaryResp
Statistiques
StatsForLastMonthByDzRespStatsForLastYearByDzResp
8. Mappage avec AutoMapper
8.1 Configuration AutoMapper
Le fichier Mapper contient le profile d'AutoMapper pour mapper entre :
- Domain entities (Aircraft, User, Jump, etc.)
- DTOs (AircraftResp, UserResp, JumpResp, etc.)
public class ModelProfile : Profile
{
public ModelProfile()
{
// Configuration des mappages
CreateMap<User, UserResp>();
CreateMap<Aircraft, AircraftResp>();
CreateMap<Jump, JumpResp>();
// ... etc
}
}
8.2 Utilisation dans les Contrôleurs
public JumpListResp Get()
{
var tmp = _jumpService.GetAllJumps();
var result = new JumpListResp
{
Rows = _mapper.Map<IEnumerable<JumpResp>>(tmp),
Count = tmp.Count()
};
return result;
}
9. Authentification JWT
9.1 Configuration JWT (Startup.cs)
var jwtSection = Configuration.GetSection("JWT");
services.Configure<JwtSettings>(jwtSection);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings.Issuer,
ValidAudience = jwtSettings.Issuer,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(jwtSettings.Passphrase))
};
});
9.2 Token Generation (UserController)
private string CreateToken(UserResp foundUser)
{
var key = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_jwtConf.Passphrase));
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _jwtConf.Issuer,
audience: _jwtConf.Issuer,
expires: DateTime.Now.AddDays(1),
signingCredentials: credentials,
claims: new Claim[]
{
new Claim(ClaimTypes.Name, foundUser.Login),
new Claim(ClaimTypes.UserData, foundUser.Id.ToString()),
new Claim(ClaimTypes.Email, foundUser.Email),
new Claim(ClaimTypes.Role, foundUser.Roles),
new Claim("Language", foundUser.Language ?? "")
});
return new JwtSecurityTokenHandler().WriteToken(token);
}
10. Endpoints API Disponibles
10.1 Routes par Contrôleur
/api/Jump
GET /api/Jump- Liste tous les sautsGET /api/Jump/{id}- Get par IDGET /api/Jump/{beginJumpIndex}/{endJumpIndex}- PaginationPOST /api/Jump- Créer un sautPUT /api/Jump/{id}- Mettre à jourDELETE /api/Jump/{id}- Supprimer
/api/User
GET /api/User/AlwaysLogin- Vérification connexionPOST /api/User/Authenticate- AuthentificationPOST /api/User- Créer un utilisateur
/api/Aircraft
GET /api/Aircraft- ListeGET /api/Aircraft/{id}- GetGET /api/Aircraft/GetSimple- Liste simplifiéePOST /api/Aircraft- CréerPUT /api/Aircraft/{id}- Mettre à jourDELETE /api/Aircraft/{id}- Supprimer
/api/DropZone
GET /api/DropZone- ListeGET /api/DropZone/{id}- GetGET /api/DropZone/GetSimple- Liste simplifiéePOST /api/DropZone- CréerPUT /api/DropZone/{id}- Mettre à jourDELETE /api/DropZone/{id}- SupprimerPUT /api/DropZone/AddToFavorite/{id}- Ajouter aux favorisPUT /api/DropZone/RemoveToFavorite/{id}- Retirer des favoris
/api/Gear
GET /api/Gear- ListeGET /api/Gear/{id}- GetPOST /api/Gear- CréerPUT /api/Gear/{id}- Mettre à jourDELETE /api/Gear/{id}- Supprimer
/api/JumpType
GET /api/JumpType- ListeGET /api/JumpType/tunnel- Types pour tunnelGET /api/JumpType/{id}- GetPOST /api/JumpType- CréerPUT /api/JumpType/{id}- Mettre à jourDELETE /api/JumpType/{id}- Supprimer
/api/Tunnel
GET /api/Tunnel- ListeGET /api/Tunnel/{id}- Get
/api/TunnelFlight
- Routes pour gestion des vols tunnel
/api/Image
GET /api/Image- ListeGET /api/Image/{id}- GetPOST /api/Image- CréerPUT /api/Image/{id}- Mettre à jourDELETE /api/Image/{id}- Supprimer
/api/Stats
GET /api/Stats/ByAircraft- Stats par aéronefGET /api/Stats/ByDz- Stats par zoneGET /api/Stats/ByGear- Stats par équipementGET /api/Stats/ByJumpType- Stats par typeGET /api/Stats/ByYear- Stats par annéeGET /api/Stats/ByYearByJumpType- Stats croiséesGET /api/Stats/ForLastMonth- Stats du mois dernierGET /api/Stats/ForLastYear- Stats de l'année dernièreGET /api/Stats/Simple- Résumé simpleGET /api/Stats/Reset- Réinitialiser les stats
11. Gestion de Configuration
11.1 Fichiers appsettings
Les configurations sont stockées dans :
appsettings.json- Configuration par défautappsettings.Development.json- Configuration de développementappsettings.Release.json- Configuration de production
11.2 Sections de Configuration
- JWT - Configuration JWT (issuer, passphrase)
- Cors - Configuration CORS (frontUrl)
- ConnectionStrings - Connexion LiteDB (Filename)
12. Initialisation de la Base de Données
Le fichier CheckAndInitDb dans Startup.cs s'assure que :
- Le fichier LiteDB existe
- Si non,
InitDbService.GenerateDb()crée la structure - Si oui,
InitDbService.Update()met à jour la structure
13. Bonnes Pratiques Observées
13.1 Séparation des Responsabilités
- Les contrôleurs ne font que manipuler les requêtes/réponses
- La logique métier est dans les services
- L'accès aux données est dans les repositories
13.2 Sécurité
- Authentification JWT
- Autorisation par rôle (admin flag)
- Validation des tokens
- HSTS en production
13.3 Gestion des Erreurs
- Développement avec
UseDeveloperExceptionPage() - Production avec HSTS
- Gestion des erreurs via services
13.4 Performance
- Pagination des listes (par index)
- Cache avec
CacheService - AutoMapper pour éviter le code répétitif
14. Conclusion
L'API SkydiveLogs est une application C# robuste et bien structurée, utilisant :
- ASP.NET Core MVC avec API
- LiteDB comme base de données fichier
- JWT pour l'authentification
- AutoMapper pour le mappage
- Injection de dépendances via
IocService
L'architecture en couches assure une maintenabilité et une extensibilité optimales pour une application de journalisation de parachutisme.