Skip to content

Consommation du CMS headless (point critique)

Les articles/auteurs proviennent du CMS headless accm-content-headless (Delivery API v2). Le defi : les payloads JSON ne se deserialisent PAS directement en BlockGridItem/BlockListItem/RteContent, car ces types dependent de IPublishedElement, Udi, etc., internes a Umbraco. La solution reconstruit des objets Umbraco synthetiques a partir du JSON, pour pouvoir reutiliser les modeles ModelsBuilder et les helpers Razor comme si le contenu etait local.

1. Client API (Services/HeadlessArticleService.cs)

  • Appel : GET delivery/api/v2/content/item/{id}?expand=properties[$all]&fields=properties[$all] (base URL = HeadlessCmsApiOptions.BaseUrl).
  • Transport : HttpClientExtensions.GetFromApiAsync<T> ; mode preview ajoute le header Preview: true, auth via header Api-Key ; erreurs non-2xx loggees (Serilog, niveau Warning).
  • Cache : MemoryCache, TTL HeadlessCmsApiOptions.ArticleDetailCacheSeconds (defaut 300s), cle headless:article-detail:{id}. Le mode preview bypasse le cache ; seules les reponses OK sont mises en cache.
  • Deserialisation : JsonConvert.DeserializeObject<DeliveryApiContentResponse>(json, settings) avec converters enregistres (BlockGridItemConverter, RteContentConverter).
  • HeadlessCmsApiService est la facade qui delegue aux sous-services (article/multimedia/author).

2. Converters (Converters/)

  • BlockGridItemConverter : lit { content, settings, rowSpan, columnSpan, areas }, cree les IPublishedElement via la factory, enveloppe dans GuidUdi("element", key), traite recursivement les areas imbriquees.
  • RteContentConverter : lit { markup, blocks }, cree un IPublishedElement par block, enveloppe dans BlockListItem, renvoie RteContent.Blocks.
  • PublishedTypeResolver : GetContentTypeOrThrow(alias) resout l'alias via le snapshot publie local (le content type doit exister localement), sinon exception (fail-fast).
  • HeadlessPublishedElement / HeadlessPublishedProperty : implementations legeres d'IPublishedElement/IPublishedProperty ; la valeur est evaluee paresseusement via un Func<object?>.

3. Factory (Factories/HeadlessElementFactory.cs)

CreateFromDelivery(JObject content) :

  1. Lit contentType et id, resout le content type via PublishedTypeResolver.
  2. Pour chaque property type du schema, construit un Func<object?> (valueFactory) selon l'editeur, enveloppe dans HeadlessPublishedProperty.
  3. Renvoie un HeadlessPublishedElement.

BuildValueFactoryFor(propertyType, token) dispatche par type d'editeur :

  • RTE : extrait markup -> HtmlEncodedString.
  • MediaPicker3 : single ou array -> MediaWithCrops (stub HeadlessPublishedMedia + ImageCropperValue, URL prefixee par DomainUrl, focal/crops) ; fallback URL brute.
  • BlockList : array ou { items } -> recursion CreateFromDelivery sur content/settings -> BlockListItem -> BlockListModel.
  • BlockGrid : lit gridColumns, reutilise BlockGridItemConverter pour les areas imbriquees -> BlockGridModel.
  • Types simples : conversion typee (bool, int, float, string).

HeadlessPublishedMedia (Factories/HeadlessPublishedMedia.cs) : stub minimal d'IPublishedContent pour les medias (Key, Name, ContentType).

4. Typage fort en vue : AsModel<T> (Extensions/PublishedElementExtensions.cs)

csharp
var content = Model.Content.AsModel<AccordionBlock>(PublishedValueFallback);
  • Si l'element est deja du bon type (contenu local), le retourne tel quel.
  • Sinon, par reflexion, invoque le constructeur ModelsBuilder ctor(IPublishedElement, IPublishedValueFallback) et renvoie le modele fort. Les getters du modele (.Title, ...) declenchent alors les valueFactory.

5. Flux JSON -> HTML

Delivery API (JSON) -> deserialisation avec converters -> HeadlessElementFactory reconstruit les IPublishedElement (valeurs paresseuses) -> les vues/partials appellent AsModel<T> puis les helpers Umbraco (Html.GetBlockGridHtmlAsync, rendu RTE par block) exactement comme pour du contenu local. Le RTE remplace les placeholders <umb-rte-block .../> par le HTML des blocks rendus.

Config & helpers

  • Configurations/HeadlessCmsApiOptions.cs : BaseUrl, ApiKey, DomainUrl (prefixe des URLs media), ArticleDetailCacheSeconds, WebhookSecret.
  • Helpers/HeadlessJsonPaths.cs : alias de content type (accmArticle, icogneArticle, linfoArticle, genericArticle ; + dossiers) et chemins JSON (properties.title, properties.datePublished, properties.teaser.markup, auteurs, ...).
  • Invalidation de cache : le headless POST un webhook (WebhookSecret) au changement d'article.

Caracteristiques cles

Evaluation paresseuse des valeurs ; dispatch par type d'editeur ; recursion pour les blocks imbriques ; reutilisation du converter au niveau article ET dans la factory ; fallback (URL media brute, commentaire HTML si partial manquant) ; mode preview (bypass cache + header).

Contributors

No contributors

Changelog

No recent changes