refactor: simplifier les actions du contrôleur en supprimant les contrôles ModelState redondants et en améliorant la récupération des données
This commit is contained in:
@@ -37,11 +37,9 @@ public class ArtisteController : Controller
|
|||||||
/// <returns>Redirection.</returns>
|
/// <returns>Redirection.</returns>
|
||||||
public IActionResult Index()
|
public IActionResult Index()
|
||||||
{
|
{
|
||||||
IEnumerable<Artiste> artistes = this.artisteRepository.FindAll();
|
IEnumerable<Artiste> artistes = this.artisteRepository.FindAll().OrderBy(t => t.Nom);
|
||||||
|
|
||||||
var artistes_ordre = artistes.OrderBy(t => t.Nom).ToList();
|
return this.View(artistes);
|
||||||
|
|
||||||
return this.View(artistes_ordre);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -61,14 +59,6 @@ public class ArtisteController : Controller
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult Create(ArtisteCreateViewModel model)
|
public IActionResult Create(ArtisteCreateViewModel model)
|
||||||
{
|
{
|
||||||
// vérifier si les données sont corrects.
|
|
||||||
if (!this.ModelState.IsValid)
|
|
||||||
{
|
|
||||||
// Passer model en paramètre afin que
|
|
||||||
// l'utilisateur conserve sa saissie.
|
|
||||||
return this.View(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Créer un objet Artiste avecc les paramètres.
|
// Créer un objet Artiste avecc les paramètres.
|
||||||
var artiste = new Artiste
|
var artiste = new Artiste
|
||||||
{
|
{
|
||||||
@@ -115,11 +105,6 @@ public class ArtisteController : Controller
|
|||||||
Biographie = model.Biographie,
|
Biographie = model.Biographie,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!this.ModelState.IsValid)
|
|
||||||
{
|
|
||||||
return this.View(artiste);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.artisteRepository.Update(artiste);
|
this.artisteRepository.Update(artiste);
|
||||||
|
|
||||||
return this.RedirectToAction("Index");
|
return this.RedirectToAction("Index");
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ namespace Webzine.WebApplication.Areas.Administration.Controllers
|
|||||||
using Webzine.Repository.Contracts;
|
using Webzine.Repository.Contracts;
|
||||||
using Webzine.WebApplication.Areas.Administration.ViewModels.Commentaire;
|
using Webzine.WebApplication.Areas.Administration.ViewModels.Commentaire;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
[Area("Administration")]
|
[Area("Administration")]
|
||||||
public class CommentaireController : Controller
|
public class CommentaireController : Controller
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class DashboardController : Controller
|
|||||||
/// <returns>La vue Index du tableau de bord.</returns>
|
/// <returns>La vue Index du tableau de bord.</returns>
|
||||||
public IActionResult Index()
|
public IActionResult Index()
|
||||||
{
|
{
|
||||||
DashboardDTO data = dashboardService.GetDashboardData();
|
DashboardDTO data = this.dashboardService.GetDashboardData();
|
||||||
|
|
||||||
return this.View(data);
|
return this.View(data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,11 +63,6 @@ public class StyleController : Controller
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult Create(StyleCreateViewModel model)
|
public IActionResult Create(StyleCreateViewModel model)
|
||||||
{
|
{
|
||||||
if (!this.ModelState.IsValid)
|
|
||||||
{
|
|
||||||
return this.View(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
var style = new Style
|
var style = new Style
|
||||||
{
|
{
|
||||||
Libelle = model.Libelle,
|
Libelle = model.Libelle,
|
||||||
@@ -124,7 +119,6 @@ public class StyleController : Controller
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">L'identifiant du style a editer.</param>
|
/// <param name="id">L'identifiant du style a editer.</param>
|
||||||
/// <returns>La vue d'edition ou une redirection vers l'index si le style n'existe pas.</returns>
|
/// <returns>La vue d'edition ou une redirection vers l'index si le style n'existe pas.</returns>
|
||||||
[HttpGet]
|
|
||||||
public IActionResult Edit(int id)
|
public IActionResult Edit(int id)
|
||||||
{
|
{
|
||||||
var style = this.styleRepository.Find(id);
|
var style = this.styleRepository.Find(id);
|
||||||
@@ -151,11 +145,6 @@ public class StyleController : Controller
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult Edit(StyleEditViewModel model)
|
public IActionResult Edit(StyleEditViewModel model)
|
||||||
{
|
{
|
||||||
if (!this.ModelState.IsValid)
|
|
||||||
{
|
|
||||||
return this.View(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
var style = this.styleRepository.Find(model.IdStyle);
|
var style = this.styleRepository.Find(model.IdStyle);
|
||||||
if (style == null)
|
if (style == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -95,13 +95,8 @@ public class TitreController : Controller
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult Create(TitreAdminDTO model)
|
public IActionResult Create(TitreAdminDTO model)
|
||||||
{
|
{
|
||||||
if (this.ModelState.IsValid)
|
this.titreAdminService.CreerTitre(model);
|
||||||
{
|
return this.RedirectToAction("Index");
|
||||||
this.titreAdminService.CreerTitre(model);
|
|
||||||
return this.RedirectToAction("Index");
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.View(model);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -152,13 +147,8 @@ public class TitreController : Controller
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult Edit(TitreAdminDTO model)
|
public IActionResult Edit(TitreAdminDTO model)
|
||||||
{
|
{
|
||||||
if (this.ModelState.IsValid)
|
this.titreAdminService.ModifierTitre(model);
|
||||||
{
|
return this.RedirectToAction("Index");
|
||||||
this.titreAdminService.ModifierTitre(model);
|
|
||||||
return this.RedirectToAction("Index");
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.View(model);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="logger">Service de journalisation injecté pour enregistrer les événements et les erreurs.</param>
|
/// <param name="logger">Service de journalisation injecté pour enregistrer les événements et les erreurs.</param>
|
||||||
/// <param name="configuration">Service d'injection de configuration pour accéder aux paramètres de l'application.</param>
|
/// <param name="configuration">Service d'injection de configuration pour accéder aux paramètres de l'application.</param>
|
||||||
|
/// <param name="titreRepository"></param>
|
||||||
public AccueilController(
|
public AccueilController(
|
||||||
ILogger<AccueilController> logger,
|
ILogger<AccueilController> logger,
|
||||||
IConfiguration configuration,
|
IConfiguration configuration,
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ namespace Webzine.WebApplication.Controllers;
|
|||||||
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controller de version de l'API.
|
||||||
|
/// </summary>
|
||||||
public class ApiController : ControllerBase
|
public class ApiController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILogger<ApiController> logger;
|
private readonly ILogger<ApiController> logger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ApiController"/> class.
|
|
||||||
/// Initialise une nouvelle instance de la classe <see cref="ApiController"/>.
|
/// Initialise une nouvelle instance de la classe <see cref="ApiController"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="logger">Service de journalisation injecté pour enregistrer les événements et les erreurs.</param>
|
/// <param name="logger">Service de journalisation injecté pour enregistrer les événements et les erreurs.</param>
|
||||||
@@ -21,7 +23,6 @@ public class ApiController : ControllerBase
|
|||||||
/// Endpoint de test pour vérifier que l'API fonctionne correctement. Retourne un objet JSON contenant le nom et la version de l'application.
|
/// Endpoint de test pour vérifier que l'API fonctionne correctement. Retourne un objet JSON contenant le nom et la version de l'application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Un objet JSON avec les propriétés "nom" et "version".</returns>
|
/// <returns>Un objet JSON avec les propriétés "nom" et "version".</returns>
|
||||||
[HttpGet]
|
|
||||||
public IActionResult Version()
|
public IActionResult Version()
|
||||||
{
|
{
|
||||||
this.logger.LogInformation("Get Version was called");
|
this.logger.LogInformation("Get Version was called");
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
using Webzine.Repository.Contracts;
|
using Webzine.Repository.Contracts;
|
||||||
using Webzine.WebApplication.ViewModels.Artiste;
|
using Webzine.WebApplication.ViewModels.Artiste;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
public class ArtisteController : Controller
|
public class ArtisteController : Controller
|
||||||
{
|
{
|
||||||
// Injection du logger via le constructeur
|
// Injection du logger via le constructeur
|
||||||
@@ -16,6 +19,7 @@
|
|||||||
/// Initialise une nouvelle instance du <see cref="ArtisteController"/>. avec un service de journalisation injecté.
|
/// Initialise une nouvelle instance du <see cref="ArtisteController"/>. avec un service de journalisation injecté.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="logger">Service de journalisation injecté pour enregistrer les événements et les erreurs.</param>
|
/// <param name="logger">Service de journalisation injecté pour enregistrer les événements et les erreurs.</param>
|
||||||
|
/// <param name="artisteRepository"></param>
|
||||||
public ArtisteController(
|
public ArtisteController(
|
||||||
ILogger<ArtisteController> logger,
|
ILogger<ArtisteController> logger,
|
||||||
IArtisteRepository artisteRepository)
|
IArtisteRepository artisteRepository)
|
||||||
|
|||||||
@@ -9,12 +9,21 @@ namespace Webzine.WebApplication.Controllers
|
|||||||
using Webzine.Repository.Contracts;
|
using Webzine.Repository.Contracts;
|
||||||
using Webzine.WebApplication.ViewModels.Recherche;
|
using Webzine.WebApplication.ViewModels.Recherche;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
public class RechercheController : Controller
|
public class RechercheController : Controller
|
||||||
{
|
{
|
||||||
private readonly ILogger<RechercheController> logger;
|
private readonly ILogger<RechercheController> logger;
|
||||||
private readonly ITitreRepository titreRepository;
|
private readonly ITitreRepository titreRepository;
|
||||||
private readonly IArtisteRepository artisteRepository;
|
private readonly IArtisteRepository artisteRepository;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialise une nouvelle instance de la classe <see cref="RechercheController"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logger"></param>
|
||||||
|
/// <param name="titreRepository"></param>
|
||||||
|
/// <param name="artisteRepository"></param>
|
||||||
public RechercheController(
|
public RechercheController(
|
||||||
ILogger<RechercheController> logger,
|
ILogger<RechercheController> logger,
|
||||||
ITitreRepository titreRepository,
|
ITitreRepository titreRepository,
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ namespace Webzine.WebApplication.Controllers
|
|||||||
this.titreRepository.IncrementNbLikes(titre);
|
this.titreRepository.IncrementNbLikes(titre);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.RedirectToAction("Details", new { id = model.IdTitre });
|
return this.RedirectToAction("Index", new { id = model.IdTitre });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -130,12 +130,6 @@ namespace Webzine.WebApplication.Controllers
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult Comment(TitreComment model)
|
public IActionResult Comment(TitreComment model)
|
||||||
{
|
{
|
||||||
if (!this.ModelState.IsValid)
|
|
||||||
{
|
|
||||||
this.logger.LogWarning("Echec de validation du modele de commentaire pour le titre ID {Id}.", model.IdTitre);
|
|
||||||
return this.RedirectToAction("Details", new { id = model.IdTitre });
|
|
||||||
}
|
|
||||||
|
|
||||||
var titre = this.titreRepository.Find(model.IdTitre);
|
var titre = this.titreRepository.Find(model.IdTitre);
|
||||||
|
|
||||||
if (titre == null)
|
if (titre == null)
|
||||||
@@ -156,7 +150,7 @@ namespace Webzine.WebApplication.Controllers
|
|||||||
|
|
||||||
this.logger.LogInformation("Commentaire ajoute avec succes au titre ID {Id}.", model.IdTitre);
|
this.logger.LogInformation("Commentaire ajoute avec succes au titre ID {Id}.", model.IdTitre);
|
||||||
|
|
||||||
return this.RedirectToAction("Details", new { id = model.IdTitre });
|
return this.RedirectToAction("Index", new { id = model.IdTitre });
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TitreStyleItem MapTitreItem(Titre titre)
|
private static TitreStyleItem MapTitreItem(Titre titre)
|
||||||
|
|||||||
42
Webzine.WebApplication/Filters/GlobalExceptionFilter.cs
Normal file
42
Webzine.WebApplication/Filters/GlobalExceptionFilter.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
namespace Webzine.WebApplication.Filters;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filtre d'exception global qui intercepte toute exception non gérée et la journalise automatiquement.
|
||||||
|
/// </summary>
|
||||||
|
public class GlobalExceptionFilter : IExceptionFilter
|
||||||
|
{
|
||||||
|
private readonly ILogger<GlobalExceptionFilter> logger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="GlobalExceptionFilter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logger">Service de journalisation injecté.</param>
|
||||||
|
public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void OnException(ExceptionContext context)
|
||||||
|
{
|
||||||
|
this.logger.LogError(
|
||||||
|
context.Exception,
|
||||||
|
"Erreur non gérée dans {Action} : {Message}",
|
||||||
|
context.ActionDescriptor.DisplayName,
|
||||||
|
context.Exception.Message);
|
||||||
|
|
||||||
|
context.Result = new ObjectResult(new
|
||||||
|
{
|
||||||
|
erreur = "Une erreur inattendue est survenue.",
|
||||||
|
detail = context.Exception.Message,
|
||||||
|
})
|
||||||
|
{
|
||||||
|
StatusCode = StatusCodes.Status500InternalServerError,
|
||||||
|
};
|
||||||
|
|
||||||
|
context.ExceptionHandled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
73
Webzine.WebApplication/Filters/ValidationActionFilter.cs
Normal file
73
Webzine.WebApplication/Filters/ValidationActionFilter.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
namespace Webzine.WebApplication.Filters;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filtre d'action qui valide automatiquement le ModelState avant l'exécution du contrôleur.
|
||||||
|
/// Mesure également le temps d'exécution de chaque action (niveau Trace).
|
||||||
|
/// </summary>
|
||||||
|
public class ValidationActionFilter : IActionFilter
|
||||||
|
{
|
||||||
|
private readonly ILogger<ValidationActionFilter> logger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ValidationActionFilter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logger">Service de journalisation injecté.</param>
|
||||||
|
public ValidationActionFilter(ILogger<ValidationActionFilter> logger)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void OnActionExecuting(ActionExecutingContext context)
|
||||||
|
{
|
||||||
|
if (!context.ModelState.IsValid)
|
||||||
|
{
|
||||||
|
var erreurs = context.ModelState
|
||||||
|
.Where(e => e.Value?.Errors.Count > 0)
|
||||||
|
.Select(e => $"{e.Key}: {string.Join(", ", e.Value!.Errors.Select(err => err.ErrorMessage))}")
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
this.logger.LogWarning(
|
||||||
|
"Validation échouée pour {Action} : {Erreurs}",
|
||||||
|
context.ActionDescriptor.DisplayName,
|
||||||
|
string.Join(" | ", erreurs));
|
||||||
|
|
||||||
|
string actionName = context.RouteData.Values["action"]?.ToString() ?? string.Empty;
|
||||||
|
|
||||||
|
// cas spécial: titre details
|
||||||
|
if (actionName.Equals("Index", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
context.Result = new RedirectResult("/");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Récupère le modèle soumis (premier argument de l'action, s'il existe)
|
||||||
|
object? model = context.ActionArguments.Values.FirstOrDefault();
|
||||||
|
|
||||||
|
if (context.Controller is Controller controller)
|
||||||
|
{
|
||||||
|
context.Result = new ViewResult
|
||||||
|
{
|
||||||
|
ViewName = actionName,
|
||||||
|
ViewData = new Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary(
|
||||||
|
controller.ViewData)
|
||||||
|
{
|
||||||
|
Model = model,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Result = new BadRequestObjectResult(context.ModelState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void OnActionExecuted(ActionExecutedContext context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ using Webzine.Repository;
|
|||||||
using Webzine.Repository.Contracts;
|
using Webzine.Repository.Contracts;
|
||||||
using Webzine.WebApplication.Configuration;
|
using Webzine.WebApplication.Configuration;
|
||||||
using Webzine.WebApplication.Extensions;
|
using Webzine.WebApplication.Extensions;
|
||||||
|
using Webzine.WebApplication.Filters;
|
||||||
using Webzine.WebApplication.Interceptors;
|
using Webzine.WebApplication.Interceptors;
|
||||||
|
|
||||||
// Initiation du logger NLog pour la classe courante afin de pouvoir l'utiliser pour logger des messages d'information, d'erreur, etc avant la construction de l'application.
|
// Initiation du logger NLog pour la classe courante afin de pouvoir l'utiliser pour logger des messages d'information, d'erreur, etc avant la construction de l'application.
|
||||||
@@ -27,8 +28,11 @@ try
|
|||||||
|
|
||||||
// Ajoute les services necessaires pour permettre l'utilisation des
|
// Ajoute les services necessaires pour permettre l'utilisation des
|
||||||
// controllers avec des vues.
|
// controllers avec des vues.
|
||||||
builder.Services.AddControllersWithViews()
|
builder.Services.AddControllersWithViews(options =>
|
||||||
|
{
|
||||||
|
options.Filters.Add<ValidationActionFilter>();
|
||||||
|
options.Filters.Add<GlobalExceptionFilter>();
|
||||||
|
})
|
||||||
// Ajoute la compilation des vues lors de l'execution de l'application.
|
// Ajoute la compilation des vues lors de l'execution de l'application.
|
||||||
// Cela nous evite de recompiler l'application a chaque modification de vue.
|
// Cela nous evite de recompiler l'application a chaque modification de vue.
|
||||||
// Necessite le package Nuget Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.
|
// Necessite le package Nuget Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.
|
||||||
@@ -87,6 +91,9 @@ try
|
|||||||
builder.Services.AddScoped<IDashboardService, DashboardService>();
|
builder.Services.AddScoped<IDashboardService, DashboardService>();
|
||||||
builder.Services.AddScoped<ITitreAdminService, TitreAdminService>();
|
builder.Services.AddScoped<ITitreAdminService, TitreAdminService>();
|
||||||
|
|
||||||
|
builder.Services.AddScoped<ValidationActionFilter>();
|
||||||
|
builder.Services.AddScoped<GlobalExceptionFilter>();
|
||||||
|
|
||||||
// https://learn.microsoft.com/fr-fr/aspnet/core/performance/response-compression?view=aspnetcore-10.0#configuration
|
// 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.
|
// 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();
|
builder.Services.AddResponseCompression();
|
||||||
|
|||||||
@@ -133,8 +133,7 @@
|
|||||||
<textarea name="Contenu"
|
<textarea name="Contenu"
|
||||||
rows="3"
|
rows="3"
|
||||||
class="form-control input-full"
|
class="form-control input-full"
|
||||||
placeholder="Votre commentaire..."
|
placeholder="Votre commentaire..."></textarea>
|
||||||
required></textarea>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -156,7 +155,7 @@
|
|||||||
|
|
||||||
<h4 class="mb-4">Commentaires</h4>
|
<h4 class="mb-4">Commentaires</h4>
|
||||||
|
|
||||||
@if (Model.Details.Commentaires != null && Model.Details.Commentaires.Any())
|
@if (Model.Details.Commentaires.Any())
|
||||||
{
|
{
|
||||||
foreach (var comment in Model.Details.Commentaires.OrderByDescending(c => c.DateCreation))
|
foreach (var comment in Model.Details.Commentaires.OrderByDescending(c => c.DateCreation))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<div class="d-flex align-items-start my-3">
|
<div class="d-flex align-items-start my-3">
|
||||||
|
|
||||||
<!-- Image -->
|
<!-- Image -->
|
||||||
<a asp-action="Details"
|
<a asp-action="Index"
|
||||||
asp-route-id="@titre.IdTitre"
|
asp-route-id="@titre.IdTitre"
|
||||||
class="me-3 text-black">
|
class="me-3 text-black">
|
||||||
<img src="@titre.UrlJaquette" alt="@titre.Libelle" width="70px" height="70px" class="object-fit-cover" loading="lazy"/>
|
<img src="@titre.UrlJaquette" alt="@titre.Libelle" width="70px" height="70px" class="object-fit-cover" loading="lazy"/>
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
@titre.ArtisteNom
|
@titre.ArtisteNom
|
||||||
</a>
|
</a>
|
||||||
-
|
-
|
||||||
<a asp-action="Details"
|
<a asp-action="Index"
|
||||||
asp-route-id="@titre.IdTitre">
|
asp-route-id="@titre.IdTitre">
|
||||||
@titre.Libelle
|
@titre.Libelle
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
layout="${longdate}|${level:uppercase=true}|${logger}|${message} ${exception:format=tostring}|${aspnet-request-url:whenEmpty=NoRequest}" />
|
layout="${longdate}|${level:uppercase=true}|${logger}|${message} ${exception:format=tostring}|${aspnet-request-url:whenEmpty=NoRequest}" />
|
||||||
|
|
||||||
<!-- Console pour debug immédiat -->
|
<!-- Console pour debug immédiat -->
|
||||||
<target xsi:type="Console" name="Info"
|
<target xsi:type="Console" name="console"
|
||||||
layout="${longdate}|${level:uppercase=true}|${logger}|${message}" />
|
layout="${longdate}|${level:uppercase=true}|${logger}|${message}" />
|
||||||
</targets>
|
</targets>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user