Skip to content

Patterns - comment ajouter / modifier

Ajouter un enregistrement DI / un wire-up Umbraco

Tout passe par src/Web/SiteComposer.cs (IComposer.Compose(IUmbracoBuilder builder)) :

  • DI classique : builder.Services.AddScoped<IFoo, Foo>().
  • Content finders, notification handlers, providers 2FA, etc. via les API builder.*. Eviter de mettre la logique de composition dans Program.cs (reserve au pipeline HTTP et au bootstrap).

Ajouter un content finder

  1. Implementer IContentFinder (resolution normale) ou IContentLastChanceFinder (fallback type 404).
  2. Injecter les services Umbraco par constructeur (constructeur primaire, cf. NotFoundContentFinder).
  3. Enregistrer dans SiteComposer (SetContentLastChanceFinder<T>() pour le last-chance).

Ajouter un controller sur une route technique

  1. Creer le controller dans src/Web/Controllers/ (heriter de Controller ou RenderController selon le besoin de contexte Umbraco - cf. SitemapController : RenderController).
  2. Decorer avec [Route("...")].
  3. Si la route est un chemin racine reserve (ex. ~/error/), l'ajouter a Umbraco:CMS:Global:ReservedPaths dans appsettings.json.

Ajouter une extension (helpers contenu / SEO)

Les extensions de src/Web/Extensions/ operent sur IPublishedContent et les interfaces ModelsBuilder. Pattern (cf. PageExtensions) : methode statique this IPublishedContent, test if (page is IXxxSettings settings), resolution par priorite (head title -> meta title -> nom de page). Ajouter la methode dans le fichier d'extension adequat (PageExtensions, DateTimeExtensions, MediaWithCropsExtensions, PublishedContentExtensions, UmbracoContextExtensions).

Ajouter / modifier un document type

Editer via le backoffice Umbraco puis laisser uSync exporter (ExportOnSave="Settings") les .config sous src/Web/uSync/v17/, OU ecrire le .config directement. Les modeles ModelsBuilder (umbraco/Models/*.generated.cs) se regenerent automatiquement (SourceCodeAuto). Voir ../modules/content-model.md.

Accéder au contenu - typer au maximum, ne pas deviner les alias

Règle : on lit le contenu par les modèles générés ModelsBuilder, pas par des chaînes de caractères. Model.Value<T>("alias") et content.GetProperty("alias") ne sont pas vérifiés par le compilateur : une faute de frappe ou un alias renommé dans le backoffice donne null en silence, et la page s'affiche avec un champ vide au lieu d'échouer.

Les modèles générés rendent au contraire l'erreur visible au build.

Ce qu'on écrit

Au lieu deÉcrire
Model.Value<string>("articleDate")@inherits UmbracoViewPage<ArticlePage> puis Model.ArticleDate
Model.Value<IEnumerable<IPublishedContent>>("items")Model.Items
content.ContentType.Alias == "eventPage"content is EventPage eventPage
block.Content.ContentType.Alias == "card"block.Content as Card
node.Children().Where(c => c.ContentType.Alias == "blogPost")node.Children<BlogPost>()
Recalculer la même valeur dans trois vuesune extension typée dans Extensions/

Enumérer se fait pareil avec les surcharges génériques : Descendants<ArticlePage>(), Children<EventFolder>(), Ancestors<EventsPage>().

Les deux seules exceptions

  1. Contenu hétérogène : un service qui traite n'importe quel doctype sans savoir lequel (indexation, recherche, sitemap). Il n'existe pas de type commun à cibler.
  2. Vue ou helper générique paramétré par un alias : un template partagé par N document types, typiquement une page qui rend une Block Grid quel que soit le doctype de la page. C'est le cas d'un modèle multi-site ou multi-marque, où Model.Value<BlockGridModel>("contentBlocks") est volontaire : c'est ce qui permet à un seul Razor de servir tous les doctypes.

Hors de ces deux cas, un Value<T>("...") est un typage qu'on a renoncé à faire.

Si le modèle n'existe pas encore, DEMANDER la régénération

Le cas qui arrive tout le temps : on vient d'ajouter un document type ou une propriété en écrivant le .config uSync, et la classe correspondante n'est pas dans umbraco/Models/. Le code typé ne compile donc pas.

Ne pas contourner en écrivant Model.Value<T>("alias"). Ce repli traverse la revue sans se faire voir, compile, et laisse une chaîne magique définitive dans le code.

Demander à l'utilisateur de régénérer les modèles, et attendre. La régénération suppose de lancer le site et de passer par le backoffice : un agent ne peut pas la faire seul. C'est un point d'arrêt normal, pas un échec. Procédure complète : ../domain/workflows.md, section "Régénérer les modèles ModelsBuilder".

Formulation type : "Le document type X est écrit dans uSync mais son modèle n'est pas encore généré, donc je ne peux pas typer la vue. Peux-tu lancer le site et régénérer les modèles ? Je reprends ensuite avec Model.<Propriete>."

Vérifier après régénération

Après un cycle de régénération, contrôler la ligne de déclaration de la classe, pas seulement que la solution compile :

csharp
public partial class ArticlePage : PublishedContentModel, IPageSettings

Une composition absente de cette liste veut dire que le contenu typé remontera null au runtime sans que rien n'échoue au build.

Ajouter un theme frontend

Creer src/Web/styles/themes/<nom>/main.scss (importer Bootstrap et les partials base/). Vite globbe automatiquement les themes/*/main.scss et genere wwwroot/css/<nom>/main.css. Eventuellement un _bootstrap_variables.scss par theme pour surcharger les tokens. Voir ../architecture/frontend-build.md.

Ajouter un module JS

Creer src/Web/scripts/modules/<nom>.js exportant un objet avec init(), et l'importer en lazy depuis scripts/index.js (await import("./modules/<nom>")). Respecter ESLint (prefer-const, no-var, eqeqeq, prefer-template, ...).

Ajouter un outil marketing / analytics

Procedure dediee (consentement obligatoire) dans ../modules/cookies-marketing.md.

Ajouter un test

Reproduire le chemin de la source : src/Web/Services/Foo.cs -> tests/Web/Services/FooTests.cs. Heriter de TestBase (Tests.Common). xUnit ([Fact]/[Theory]) + Moq.

Contributors

No contributors

Changelog

No recent changes