diff --git a/Webzine.WebApplication/Areas/Administration/ViewModels/DashboardViewModel.cs b/Webzine.Business.Contracts/Dto/DashboardDTO.cs
similarity index 90%
rename from Webzine.WebApplication/Areas/Administration/ViewModels/DashboardViewModel.cs
rename to Webzine.Business.Contracts/Dto/DashboardDTO.cs
index 106779d..9509c6c 100644
--- a/Webzine.WebApplication/Areas/Administration/ViewModels/DashboardViewModel.cs
+++ b/Webzine.Business.Contracts/Dto/DashboardDTO.cs
@@ -1,9 +1,9 @@
-namespace Webzine.WebApplication.Areas.Administration.ViewModels;
+namespace Webzine.Business.Contracts.Dto;
///
-/// ViewModel pour le tableau de bord de l'administration du webzine.
+/// DTO pour le tableau de bord de l'administration du webzine.
///
-public class DashboardViewModel
+public class DashboardDTO
{
///
/// Définit le nombre total d'artistes chroniqués dans le webzine.
diff --git a/Webzine.Business.Contracts/IDashboardService.cs b/Webzine.Business.Contracts/IDashboardService.cs
new file mode 100644
index 0000000..8bde456
--- /dev/null
+++ b/Webzine.Business.Contracts/IDashboardService.cs
@@ -0,0 +1,16 @@
+using Webzine.Business.Contracts.Dto;
+
+namespace Webzine.Business.Contracts;
+
+///
+/// Service responsable du calcul des statistiques affichées sur le tableau de bord d'administration.
+/// Agrège les données provenant de plusieurs repositories pour produire un résumé cohérent.
+///
+public interface IDashboardService
+{
+ ///
+ /// Calcule et retourne toutes les statistiques du tableau de bord en une seule passe.
+ ///
+ /// Un contenant les agrégats calculés.
+ DashboardDTO GetDashboardData();
+}
\ No newline at end of file
diff --git a/Webzine.Business/DashboardService.cs b/Webzine.Business/DashboardService.cs
new file mode 100644
index 0000000..d9e9812
--- /dev/null
+++ b/Webzine.Business/DashboardService.cs
@@ -0,0 +1,71 @@
+using Webzine.Business.Contracts;
+using Webzine.Entity;
+using Webzine.Repository.Contracts;
+
+namespace Webzine.Business;
+
+using Contracts.Dto;
+
+///
+/// Implémentation de .
+/// Orchestre plusieurs appels aux repositories pour produire les statistiques du tableau de bord.
+///
+public class DashboardService : IDashboardService
+{
+ private readonly IArtisteRepository artisteRepository;
+ private readonly ITitreRepository titreRepository;
+ private readonly IStyleRepository styleRepository;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Repository des artistes.
+ /// Repository des titres.
+ /// Repository des styles.
+ public DashboardService(
+ IArtisteRepository artisteRepository,
+ ITitreRepository titreRepository,
+ IStyleRepository styleRepository)
+ {
+ this.artisteRepository = artisteRepository;
+ this.titreRepository = titreRepository;
+ this.styleRepository = styleRepository;
+ }
+
+ ///
+ public DashboardDTO GetDashboardData()
+ {
+ IEnumerable titres = this.titreRepository.FindAll();
+
+ Artiste? artisteLePlusChronique = titres
+ .GroupBy(t => t.Artiste)
+ .OrderByDescending(g => g.Count())
+ .FirstOrDefault()
+ ?.Key;
+
+ Artiste? albumLePlusChronique = titres
+ .GroupBy(t => (t.Artiste, t.Album))
+ .GroupBy(g => g.Key.Artiste)
+ .OrderByDescending(g => g.Count())
+ .FirstOrDefault()
+ ?.Key;
+
+ Titre? musiqueLaPlusJouee = titres
+ .OrderByDescending(t => t.NbLectures)
+ .FirstOrDefault();
+
+ return new DashboardDTO
+ {
+ NombreArtistes = this.artisteRepository.Count(),
+ ArtisteLePlusChronique = artisteLePlusChronique.Nom,
+ AlbumLePlusChronique = albumLePlusChronique.Nom,
+ NombreBiographies = this.artisteRepository.Count(a => !string.IsNullOrEmpty(a.Biographie)),
+ IdMusiqueLaPlusJouee = musiqueLaPlusJouee.IdTitre,
+ MusiqueLaPlusJouee = musiqueLaPlusJouee.Libelle,
+ NombreTitres = this.titreRepository.Count(),
+ NombreGenres = this.styleRepository.Count(),
+ NombreLectures = titres.Sum(t => t.NbLectures),
+ NombreLikes = titres.Sum(t => t.NbLikes),
+ };
+ }
+}
\ No newline at end of file
diff --git a/Webzine.Business/Webzine.Business.csproj b/Webzine.Business/Webzine.Business.csproj
index 33c0658..6e5a6aa 100644
--- a/Webzine.Business/Webzine.Business.csproj
+++ b/Webzine.Business/Webzine.Business.csproj
@@ -21,4 +21,9 @@
+
+
+
+
+
diff --git a/Webzine.Repository.Contracts/IArtisteRepository.cs b/Webzine.Repository.Contracts/IArtisteRepository.cs
index bc13f76..ee170b5 100644
--- a/Webzine.Repository.Contracts/IArtisteRepository.cs
+++ b/Webzine.Repository.Contracts/IArtisteRepository.cs
@@ -51,5 +51,18 @@ namespace Webzine.Repository.Contracts
/// Nom de l'artiste.
/// IEnumarble. qui contient la chaine de caractere.
IEnumerable Search(string nom);
+
+ ///
+ /// Récupère le nombre total d'artistes dans la collection.
+ ///
+ /// Le nombre total d'artistes.
+ int Count();
+
+ ///
+ /// Récupère le nombre d'artistes correspondant au prédicat fourni.
+ ///
+ /// Le prédicat de filtrage.
+ /// Le nombre d'artistes correspondants.
+ int Count(Func predicate);
}
}
\ No newline at end of file
diff --git a/Webzine.Repository.Contracts/IStyleRepository.cs b/Webzine.Repository.Contracts/IStyleRepository.cs
index d260039..0ea9ba3 100644
--- a/Webzine.Repository.Contracts/IStyleRepository.cs
+++ b/Webzine.Repository.Contracts/IStyleRepository.cs
@@ -37,5 +37,11 @@ namespace Webzine.Repository.Contracts
///
/// L'objet style à mettre à jour.
+ /// Récupère le nombre total de styles dans la liste des styles.
+ ///
+ /// Le nombre total de styles présents dans la liste.
+ int Count();
}
}
\ No newline at end of file
diff --git a/Webzine.Repository/DbArtisteRepository.cs b/Webzine.Repository/DbArtisteRepository.cs
index c27c1d7..0b3748f 100644
--- a/Webzine.Repository/DbArtisteRepository.cs
+++ b/Webzine.Repository/DbArtisteRepository.cs
@@ -176,5 +176,37 @@ namespace Webzine.Repository
throw new Exception("Erreur lors de la recherche d'artiste {error}", ex);
}
}
+
+ ///
+ public int Count()
+ {
+ try
+ {
+ int count = this.context.Artistes.Count();
+ this.logger.LogDebug("Nombre total d'artistes dans la base: {Count}", count);
+ return count;
+ }
+ catch (Exception ex)
+ {
+ this.logger.LogError(ex, "Erreur lors du comptage des artistes.");
+ throw;
+ }
+ }
+
+ ///
+ public int Count(Func predicate)
+ {
+ try
+ {
+ int count = this.context.Artistes.Count(predicate);
+ this.logger.LogDebug("Nombre d'artistes (avec prédicat): {Count}", count);
+ return count;
+ }
+ catch (Exception ex)
+ {
+ this.logger.LogError(ex, "Erreur lors du comptage des artistes avec prédicat.");
+ throw;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/Webzine.Repository/DbStyleRepository.cs b/Webzine.Repository/DbStyleRepository.cs
index c350a4f..0a6894b 100644
--- a/Webzine.Repository/DbStyleRepository.cs
+++ b/Webzine.Repository/DbStyleRepository.cs
@@ -178,4 +178,20 @@ public class DbStyleRepository : IStyleRepository
throw;
}
}
+
+ ///
+ public int Count()
+ {
+ try
+ {
+ int count = this.context.Styles.Count();
+ this.logger.LogDebug("Nombre total de styles: {Count}", count);
+ return count;
+ }
+ catch (Exception ex)
+ {
+ this.logger.LogError(ex, "Erreur lors du comptage des styles");
+ throw;
+ }
+ }
}
\ No newline at end of file
diff --git a/Webzine.Repository/LocalArtisteRepository.cs b/Webzine.Repository/LocalArtisteRepository.cs
index 69021c5..0388da3 100644
--- a/Webzine.Repository/LocalArtisteRepository.cs
+++ b/Webzine.Repository/LocalArtisteRepository.cs
@@ -93,5 +93,17 @@ namespace Webzine.Repository
.Where(a => a.Nom.ToLower().Contains(mot.ToLower()))
.ToList();
}
+
+ ///
+ public int Count()
+ {
+ return this.dataStore.Artistes.Count;
+ }
+
+ ///
+ public int Count(Func predicate)
+ {
+ return this.dataStore.Artistes.Count(predicate);
+ }
}
}
\ No newline at end of file
diff --git a/Webzine.Repository/LocalStyleRepository.cs b/Webzine.Repository/LocalStyleRepository.cs
index 0b4d16c..e750ff2 100644
--- a/Webzine.Repository/LocalStyleRepository.cs
+++ b/Webzine.Repository/LocalStyleRepository.cs
@@ -56,4 +56,10 @@ public class LocalStyleRepository : IStyleRepository
{
throw new NotSupportedException("Mode local");
}
+
+ ///
+ public int Count()
+ {
+ return this.dataStore.Styles.Count;
+ }
}
\ No newline at end of file
diff --git a/Webzine.WebApplication/Areas/Administration/Controllers/DashboardController.cs b/Webzine.WebApplication/Areas/Administration/Controllers/DashboardController.cs
index 2f314ad..97f1721 100644
--- a/Webzine.WebApplication/Areas/Administration/Controllers/DashboardController.cs
+++ b/Webzine.WebApplication/Areas/Administration/Controllers/DashboardController.cs
@@ -1,30 +1,26 @@
namespace Webzine.WebApplication.Areas.Administration.Controllers;
+using Webzine.Business.Contracts;
+using Webzine.Business.Contracts.Dto;
using Microsoft.AspNetCore.Mvc;
-
using Webzine.Repository.Contracts;
-using Webzine.WebApplication.Areas.Administration.ViewModels;
[Area("Administration")]
public class DashboardController : Controller
{
private readonly ILogger logger;
- private readonly IStyleRepository styleRepository;
- private readonly IArtisteRepository artisteRepository;
- private readonly ITitreRepository titreRepository;
+ private readonly IDashboardService dashboardService;
///
/// Initializes a new instance of the class.
/// Initialise une nouvelle instance de la classe .
///
/// Service de journalisation injecté.
- /// Repository des styles injecté.
- public DashboardController(ILogger logger, IStyleRepository styleRepository, IArtisteRepository artisteRepository, ITitreRepository titreRepository)
+ /// Service de calcul des statistiques du tableau de bord.
+ public DashboardController(ILogger logger, IDashboardService dashboardService)
{
this.logger = logger;
- this.styleRepository = styleRepository;
- this.artisteRepository = artisteRepository;
- this.titreRepository = titreRepository;
+ this.dashboardService = dashboardService;
this.logger.LogInformation("Initialisation du contrôleur TitreController.");
}
@@ -35,42 +31,8 @@ public class DashboardController : Controller
/// La vue Index du tableau de bord.
public IActionResult Index()
{
- var artisteLePlusChronique = this.titreRepository.FindAll()
- .GroupBy(t => t.Artiste)
- .OrderByDescending(g => g.Count())
- .First();
+ DashboardDTO data = dashboardService.GetDashboardData();
- var albumLePlusChronique = this.titreRepository.FindAll()
- .GroupBy(t => t.Artiste)
- .OrderByDescending(g => g.Select(t => t.Album).Distinct().Count())
- .First();
-
- var musiqueLaPlusJouee = this.titreRepository.FindAll()
- .OrderByDescending(t => t.NbLectures)
- .First();
-
- var model = new DashboardViewModel
- {
- NombreArtistes = this.artisteRepository.FindAll().Count(),
-
- ArtisteLePlusChronique = artisteLePlusChronique.Key.Nom,
-
- AlbumLePlusChronique = albumLePlusChronique.Key.Nom,
-
- NombreBiographies = this.artisteRepository.FindAll().Count(a => !string.IsNullOrEmpty(a.Biographie)),
-
- IdMusiqueLaPlusJouee = musiqueLaPlusJouee.IdTitre,
- MusiqueLaPlusJouee = musiqueLaPlusJouee.Libelle,
-
- NombreTitres = this.titreRepository.Count(),
-
- NombreGenres = this.styleRepository.FindAll().Count(),
-
- NombreLectures = this.titreRepository.FindAll().Sum(t => t.NbLectures),
-
- NombreLikes = this.titreRepository.FindAll().Sum(t => t.NbLikes),
- };
-
- return this.View(model);
+ return this.View(data);
}
}
\ No newline at end of file
diff --git a/Webzine.WebApplication/Areas/Administration/Views/Dashboard/Index.cshtml b/Webzine.WebApplication/Areas/Administration/Views/Dashboard/Index.cshtml
index ac676f2..65217be 100644
--- a/Webzine.WebApplication/Areas/Administration/Views/Dashboard/Index.cshtml
+++ b/Webzine.WebApplication/Areas/Administration/Views/Dashboard/Index.cshtml
@@ -1,4 +1,5 @@
-@model Webzine.WebApplication.Areas.Administration.ViewModels.DashboardViewModel
+@using Webzine.Business.Contracts.Dto
+@model DashboardDTO
Tableau de bord
diff --git a/Webzine.WebApplication/Program.cs b/Webzine.WebApplication/Program.cs
index 916d86e..d118c67 100644
--- a/Webzine.WebApplication/Program.cs
+++ b/Webzine.WebApplication/Program.cs
@@ -6,6 +6,8 @@ using Microsoft.EntityFrameworkCore;
using NLog;
using NLog.Web;
+using Webzine.Business;
+using Webzine.Business.Contracts;
using Webzine.EntitiesContext;
using Webzine.Entity;
using Webzine.Entity.Fixtures;
@@ -67,6 +69,8 @@ try
builder.Services.AddSingleton();
}
+ builder.Services.AddScoped();
+
// https://learn.microsoft.com/fr-fr/aspnet/core/performance/response-compression?view=aspnetcore-10.0#configuration
// Ajoute le service de compression des réponses HTTP pour réduire la taille des données envoyées au client et améliorer les performances de l'application.
builder.Services.AddResponseCompression();
@@ -78,6 +82,8 @@ try
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService();
+ db.Database.EnsureCreated();
+
if (shouldSeed)
{
db.Database.EnsureDeleted();
diff --git a/Webzine.WebApplication/Webzine.WebApplication.csproj b/Webzine.WebApplication/Webzine.WebApplication.csproj
index f47a272..5f8c0ca 100644
--- a/Webzine.WebApplication/Webzine.WebApplication.csproj
+++ b/Webzine.WebApplication/Webzine.WebApplication.csproj
@@ -34,6 +34,8 @@
+
+