From 83eae661bf714bfa1c55c2885051a70d07df45b0 Mon Sep 17 00:00:00 2001
From: mirage <119869686+ClementBobin@users.noreply.github.com>
Date: Thu, 2 Apr 2026 10:50:19 +0200
Subject: [PATCH] =?UTF-8?q?feat=C2=A0:=20ajout=20d'un=20intercepteur=20de?=
=?UTF-8?q?=20requ=C3=AAtes=20lentes=20EF=20Core=20et=20une=20configuratio?=
=?UTF-8?q?n=20des=20options=20de=20performance?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Webzine.Business/Webzine.Business.csproj | 1 +
.../Configuration/Middlewares.cs | 13 ++
.../Interceptors/EfSlowQueryInterceptor.cs | 146 ++++++++++++++++++
Webzine.WebApplication/Program.cs | 23 ++-
Webzine.WebApplication/appsettings.json | 5 +-
5 files changed, 183 insertions(+), 5 deletions(-)
create mode 100644 Webzine.WebApplication/Configuration/Middlewares.cs
create mode 100644 Webzine.WebApplication/Interceptors/EfSlowQueryInterceptor.cs
diff --git a/Webzine.Business/Webzine.Business.csproj b/Webzine.Business/Webzine.Business.csproj
index 6e5a6aa..a2efab2 100644
--- a/Webzine.Business/Webzine.Business.csproj
+++ b/Webzine.Business/Webzine.Business.csproj
@@ -23,6 +23,7 @@
+
diff --git a/Webzine.WebApplication/Configuration/Middlewares.cs b/Webzine.WebApplication/Configuration/Middlewares.cs
new file mode 100644
index 0000000..bbfe61e
--- /dev/null
+++ b/Webzine.WebApplication/Configuration/Middlewares.cs
@@ -0,0 +1,13 @@
+namespace Webzine.WebApplication.Configuration;
+
+///
+/// Options de seuil pour la détection des opérations EF Core lentes.
+///
+public class EfPerformanceOptions
+{
+ ///
+ /// Obtient ou définit le seuil en millisecondes au-delà duquel une commande SQL est journalisée.
+ /// Valeur par défaut : 200 ms.
+ ///
+ public int SeuilMs { get; set; } = 200;
+}
diff --git a/Webzine.WebApplication/Interceptors/EfSlowQueryInterceptor.cs b/Webzine.WebApplication/Interceptors/EfSlowQueryInterceptor.cs
new file mode 100644
index 0000000..5e629a8
--- /dev/null
+++ b/Webzine.WebApplication/Interceptors/EfSlowQueryInterceptor.cs
@@ -0,0 +1,146 @@
+namespace Webzine.WebApplication.Interceptors;
+
+using System.Data.Common;
+using System.Diagnostics;
+
+using Configuration;
+
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.Extensions.Options;
+
+///
+/// Intercepteur EF Core qui journalise uniquement les commandes SQL dépassant le seuil configuré.
+/// Remonte la pile d'appels pour identifier la méthode repository (Webzine.Repository.*) à l'origine de la requête.
+///
+///
+///
+/// Références :
+///
+/// -
+/// EF Core interceptors (doc officielle) :
+///
+///
+/// -
+/// API :
+///
+///
+/// -
+/// Exemple de slow-query interceptor (SO) :
+///
+///
+/// -
+/// pour remonter l'appelant :
+///
+///
+/// -
+/// Enregistrement via AddInterceptors :
+///
+///
+///
+///
+///
+public class EfSlowQueryInterceptor : DbCommandInterceptor
+{
+ private readonly ILogger logger;
+ private readonly int seuilMs;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Le service de journalisation injecté pour suivre les opérations de l'intercepteur.
+ /// Les options de performance EF injectées pour récupérer le seuil de lenteur configuré.
+ public EfSlowQueryInterceptor(ILogger logger, IOptions options)
+ {
+ this.logger = logger;
+ this.seuilMs = options.Value.SeuilMs;
+
+ this.logger.LogDebug("[EfSlowQueryInterceptor] Constructeur appelé — seuil : {SeuilMs} ms.", this.seuilMs);
+ }
+
+ ///
+ public override DbDataReader ReaderExecuted(DbCommand command, CommandExecutedEventData eventData, DbDataReader result)
+ {
+ this.JournaliserSiLent(eventData.Duration);
+ return result;
+ }
+
+ ///
+ public override ValueTask ReaderExecutedAsync(DbCommand command, CommandExecutedEventData eventData, DbDataReader result, CancellationToken cancellationToken = default)
+ {
+ this.JournaliserSiLent(eventData.Duration);
+ return ValueTask.FromResult(result);
+ }
+
+ ///
+ public override int NonQueryExecuted(DbCommand command, CommandExecutedEventData eventData, int result)
+ {
+ this.JournaliserSiLent(eventData.Duration);
+ return result;
+ }
+
+ ///
+ public override ValueTask NonQueryExecutedAsync(DbCommand command, CommandExecutedEventData eventData, int result, CancellationToken cancellationToken = default)
+ {
+ this.JournaliserSiLent(eventData.Duration);
+ return ValueTask.FromResult(result);
+ }
+
+ ///
+ public override object? ScalarExecuted(DbCommand command, CommandExecutedEventData eventData, object? result)
+ {
+ this.JournaliserSiLent(eventData.Duration);
+ return result;
+ }
+
+ ///
+ public override ValueTask