Comment capturer les URL de pages publiées dans EpiServer 12.20.0

Comment capturer les URL de pages publiées dans EpiServer 12.20.0

Alex Rollin
Alex Rollin
August 4, 2025
Dernière mise à jour : February 15, 2026
August 4, 2025

La mise à jour vers EpiServer (maintenant Optimizely CMS) 12.20.0 peut briser votre logique de capture d'URL existante lors des événements de publication. Si vous obtenez soudainement des URL nulles ou que vos gestionnaires d'événements ne se déclenchent plus, vous n'êtes pas seul. Ce guide vous accompagne dans l'approche fiable pour capturer les URL de pages publiées dans la version mise à jour, avec des exemples de code fonctionnels et des conseils de dépannage.

Prérequis

Avant d'implémenter la capture d'URL dans EpiServer 12.20.0, assurez-vous d'avoir :

  • EpiServer CMS 12.20.0 ou ultérieur installé
  • Runtime .NET 6 ou supérieur
  • Compréhension de base de l'injection de dépendances en .NET
  • Accès pour modifier la configuration de démarrage de votre site
  • Compréhension du système d'événements de contenu d'EpiServer

Votre projet devrait déjà avoir les paquets EpiServer principaux référencés :

  • EPiServer.CMS.Core
  • EPiServer.CMS.UI

Étape 1 : Créer la classe gestionnaire d'événements

Commencez par créer une classe dédiée pour gérer les événements de contenu publié. Le changement clé dans la version 12.20.0 est d'utiliser correctement l'injection de dépendances au lieu du motif ServiceLocator obsolète.

using EPiServer;
using EPiServer.Core;
using EPiServer.Web.Routing;
using Microsoft.Extensions.Logging;

public class PageUrlCaptureHandler
{
    private readonly IContentEvents _contentEvents;
    private readonly IUrlResolver _urlResolver;
    private readonly ILogger _logger;

    public PageUrlCaptureHandler(
        IContentEvents contentEvents, 
        IUrlResolver urlResolver,
        ILogger logger)
    {
        _contentEvents = contentEvents;
        _urlResolver = urlResolver;
        _logger = logger;
        
        // S'abonner à l'événement de contenu publié
        _contentEvents.PublishedContent  = OnContentPublished;
    }

    private void OnContentPublished(object sender, ContentEventArgs e)
    {
        if (e.Content is PageData publishedPage)
        {
            CapturePageUrl(publishedPage);
        }
    }

    private void CapturePageUrl(PageData page)
    {
        // Implémentation à l'étape suivante
    }
}

Étape 2 : Implémenter la logique de capture d'URL

Ajoutez maintenant la logique réelle de capture d'URL. La partie cruciale est d'utiliser les bons VirtualPathArguments avec ContextMode.Default pour obtenir les URL publiques.

private void CapturePageUrl(PageData page)
{
    try
    {
        // Gérer les sites monolingues
        if (page.ExistingLanguages.Count() == 1)
        {
            var url = GetPublicUrl(page.ContentLink, null);
            if (!string.IsNullOrEmpty(url))
            {
                ProcessCapturedUrl(url, page.Name, null);
            }
            return;
        }

        // Gérer les sites multilingues
        foreach (var language in page.ExistingLanguages)
        {
            var url = GetPublicUrl(page.ContentLink, language.Name);
            if (!string.IsNullOrEmpty(url))
            {
                ProcessCapturedUrl(url, page.Name, language.Name);
            }
        }
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Échec de la capture d'URL pour la page {PageId}", page.ContentLink.ID);
    }
}

private string GetPublicUrl(ContentReference contentRef, string language)
{
    var args = new VirtualPathArguments
    {
        ContextMode = ContextMode.Default,
        ForceCanonical = true
    };

    return _urlResolver.GetUrl(contentRef, language, args);
}

private void ProcessCapturedUrl(string url, string pageName, string language)
{
    // Votre logique personnalisée ici - exemples :
    // - Enregistrer en base de données
    // - Envoyer au service d'analytique  
    // - Mettre à jour le plan de site
    // - Déclencher un webhook
    
    var languageInfo = string.IsNullOrEmpty(language) ? "défaut" : language;
    _logger.LogInformation("URL capturée : {Url} pour la page '{PageName}' (Langue : {Language})", 
        url, pageName, languageInfo);
}

Étape 3 : Inscrire le gestionnaire dans l'injection de dépendances

Ajoutez votre gestionnaire au conteneur de services dans votre fichier Startup.cs ou Program.cs :

public void ConfigureServices(IServiceCollection services)
{
    // Votre configuration EpiServer existante...
    
    // Inscrire le gestionnaire de capture d'URL comme singleton
    services.AddSingleton();
    
    // Alternative : Inscrire comme scoped si vous avez besoin de services par requête
    // services.AddScoped();
}

Nous avons constaté que l'inscription comme singleton fonctionne mieux pour les gestionnaires d'événements puisqu'ils doivent persister tout au long du cycle de vie de l'application.

Étape 4 : Gérer les cas particuliers et la validation

Ajoutez la validation pour gérer les pages qui pourraient ne pas avoir d'URL publiques :

private string GetPublicUrl(ContentReference contentRef, string language)
{
    // Vérifier si la référence de contenu est valide
    if (ContentReference.IsNullOrEmpty(contentRef))
        return null;

    var args = new VirtualPathArguments
    {
        ContextMode = ContextMode.Default,
        ForceCanonical = true
    };

    var url = _urlResolver.GetUrl(contentRef, language, args);
    
    // Validation supplémentaire
    if (string.IsNullOrEmpty(url) || url.StartsWith("~/"))
    {
        _logger.LogWarning("Impossible de résoudre l'URL publique pour le contenu {ContentId} (Langue : {Language})", 
            contentRef.ID, language ?? "défaut");
        return null;
    }

    return url;
}

Étape 5 : Ajouter le support pour les scénarios multi-sites

Si vous exécutez plusieurs sites, vous pourriez avoir besoin de génération d'URL spécifique aux sites :

private readonly ISiteDefinitionResolver _siteResolver;

// Ajouter aux paramètres du constructeur
public PageUrlCaptureHandler(
    IContentEvents contentEvents, 
    IUrlResolver urlResolver,
    ISiteDefinitionResolver siteResolver,
    ILogger logger)
{
    _contentEvents = contentEvents;
    _urlResolver = urlResolver;
    _siteResolver = siteResolver;
    _logger = logger;
    
    _contentEvents.PublishedContent  = OnContentPublished;
}

private string GetPublicUrlWithSite(ContentReference contentRef, string language)
{
    var site = _siteResolver.GetByContent(contentRef, true);
    if (site == null)
        return GetPublicUrl(contentRef, language);

    var args = new VirtualPathArguments
    {
        ContextMode = ContextMode.Default,
        ForceCanonical = true
    };

    return _urlResolver.GetUrl(contentRef, language, args);
}

Erreurs courantes à éviter

Utiliser le motif ServiceLocator

// NE FAITES PAS ceci - obsolète dans la version 12.20.0
var urlResolver = ServiceLocator.Current.GetInstance();

Oublier d'inscrire le gestionnaire
Si votre gestionnaire d'événements ne se déclenche pas, vérifiez qu'il est correctement inscrit dans l'injection de dépendances. Le conteneur doit l'instancier pour que l'abonnement à l'événement fonctionne.

Ne pas gérer les URL nulles
Les pages sans modèles ou celles marquées comme non-routables retourneront des URL nulles. Vérifiez toujours pour null avant de traiter.

Mode contexte incorrect

// NE PAS utiliser le mode Édition pour les URL publiques
var args = new VirtualPathArguments { ContextMode = ContextMode.Edit };

// UTILISEZ le mode Défaut pour les URL publiques  
var args = new VirtualPathArguments { ContextMode = ContextMode.Default };

Fuites mémoire des abonnements aux événements
Si vous n'utilisez pas l'injection de dépendances correctement, assurez-vous de vous désabonner des événements pour éviter les fuites mémoire :

public void Dispose()
{
    _contentEvents.PublishedContent -= OnContentPublished;
}

Tests et vérification

Tester votre implémentation

Créez une page de test simple pour vérifier que la capture d'URL fonctionne :

  • Créer une nouvelle page dans l'admin EpiServer
  • Publier la page
  • Vérifier vos journaux pour l'entrée d'URL capturée
  • Vérifier que l'URL est accessible et correcte

Déboguer les problèmes courants

Aucune URL capturée :

  • Vérifier que le gestionnaire est inscrit dans l'injection de dépendances
  • Vérifier que la page a un modèle assigné
  • Confirmer que la page est définie pour être publiée (pas seulement sauvegardée comme brouillon)

URL partielles (~/nom-page) :

  • Assurez-vous d'utiliser ContextMode.Default
  • Vérifier la configuration du nom d'hôte de votre site
  • Vérifier ForceCanonical = true dans VirtualPathArguments

Travailler avec des équipes nous a appris que le problème le plus courant est d'oublier d'inscrire correctement le gestionnaire dans le conteneur d'injection de dépendances.

Considérations de performance

Pour les sites à fort trafic, considérez rendre le traitement d'URL asynchrone :

private async void OnContentPublished(object sender, ContentEventArgs e)
{
    if (e.Content is PageData publishedPage)
    {
        // Traiter la capture d'URL en arrière-plan
        _ = Task.Run(() => CapturePageUrl(publishedPage));
    }
}

Exemple complet fonctionnel

Voici l'implémentation complète prête à utiliser :

using EPiServer;
using EPiServer.Core;
using EPiServer.Web.Routing;
using Microsoft.Extensions.Logging;

public class PageUrlCaptureHandler
{
    private readonly IContentEvents _contentEvents;
    private readonly IUrlResolver _urlResolver;
    private readonly ILogger _logger;

    public PageUrlCaptureHandler(
        IContentEvents contentEvents, 
        IUrlResolver urlResolver,
        ILogger logger)
    {
        _contentEvents = contentEvents;
        _urlResolver = urlResolver;
        _logger = logger;
        
        _contentEvents.PublishedContent  = OnContentPublished;
    }

    private void OnContentPublished(object sender, ContentEventArgs e)
    {
        if (e.Content is PageData publishedPage)
        {
            CapturePageUrl(publishedPage);
        }
    }

    private void CapturePageUrl(PageData page)
    {
        try
        {
            foreach (var language in page.ExistingLanguages)
            {
                var url = GetPublicUrl(page.ContentLink, language.Name);
                if (!string.IsNullOrEmpty(url))
                {
                    ProcessCapturedUrl(url, page.Name, language.Name);
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Échec de la capture d'URL pour la page {PageId}", page.ContentLink.ID);
        }
    }

    private string GetPublicUrl(ContentReference contentRef, string language)
    {
        if (ContentReference.IsNullOrEmpty(contentRef))
            return null;

        var args = new VirtualPathArguments
        {
            ContextMode = ContextMode.Default,
            ForceCanonical = true
        };

        var url = _urlResolver.GetUrl(contentRef, language, args);
        
        if (string.IsNullOrEmpty(url) || url.StartsWith("~/"))
        {
            return null;
        }

        return url;
    }

    private void ProcessCapturedUrl(string url, string pageName, string language)
    {
        _logger.LogInformation("URL de page publiée capturée : {Url} ({PageName}, {Language})", 
            url, pageName, language);
        
        // Ajoutez votre logique de traitement personnalisée ici
    }
}

N'oubliez pas de l'inscrire dans votre conteneur d'injection de dépendances :

services.AddSingleton();

Conclusion

Capturer les URL de pages publiées dans EpiServer 12.20.0 nécessite de s'adapter aux nouveaux modèles d'injection de dépendances et à la gestion d'événements mise à jour. Les changements clés sont l'utilisation de l'injection de dépendances appropriée au lieu de ServiceLocator, s'assurer d'avoir les bons VirtualPathArguments, et gérer appropriérement les scénarios multilingues.

Notre expérience montre que la plupart des problèmes de capture d'URL après mise à jour proviennent soit d'une inscription inappropriée dans l'injection de dépendances ou de paramètres de mode contexte incorrects. Suivre ce guide devrait vous donner une capture d'URL fiable qui fonctionne de manière cohérente dans différentes configurations de site.

Besoin d'aide pour implémenter la capture d'URL dans votre mise à jour EpiServer 12.20.0 ? Nous pouvons réviser votre code de gestion d'événements existant et vous aider à migrer vers les nouveaux modèles tout en vous assurant que vos systèmes d'analytique, de journalisation et d'intégration continuent de fonctionner correctement.

Share this article