Umbraco CMS
CloudHeartcoreDXPMarketplace
14.latest
14.latest
  • Umbraco CMS Documentation
  • Legacy Documentation
    • Our Umbraco
    • GitHub
  • Release Notes
  • Contribute
  • Sustainability Best Practices
  • Fundamentals
    • Get to know Umbraco
    • Setup
      • Requirements
      • Installation
        • Install using .NET CLI
        • Running Umbraco in Docker using Docker Compose
        • Install using Visual Studio
        • Local IIS With Umbraco
        • Install using Visual Studio Code
        • Installing Nightly Builds
        • Running Umbraco on Linux/macOS
        • Unattended Installs
      • Upgrade your project
        • Version Specific Upgrades
          • Upgrade from Umbraco 8 to the latest version
          • Migrate content to Umbraco 8
          • Minor upgrades for Umbraco 8
          • Upgrade to Umbraco 7
          • Minor upgrades for Umbraco 7
      • Server setup
        • Running Umbraco On Azure Web Apps
        • Hosting Umbraco in IIS
        • File And Folder Permissions
        • Runtime Modes
        • Umbraco in Load Balanced Environments
          • Load Balancing Azure Web Apps
          • Standalone File System
          • Advanced Techniques With Flexible Load Balancing
          • Logging With Load Balancing
    • Backoffice
      • Sections
      • Property Editors
        • Built-in Property Editors
          • Checkbox List
          • Collection
          • Color Picker
          • Content Picker
          • Document Picker
          • DateTime
          • Date
          • Decimal
          • Email Address
          • Eye Dropper Color Picker
          • File Upload
          • Image Cropper
          • Label
          • Markdown Editor
          • Media Picker
          • Member Group Picker
          • Member Picker
          • Multi Url Picker
          • Repeatable Textstrings
          • Numeric
          • Radiobutton List
          • Slider
          • Tags
          • Textarea
          • Textbox
          • Toggle
          • User Picker
          • Block Editors
            • Block Grid
            • Block List
          • Dropdown
          • Rich Text Editor
            • Rich Text Editor Configuration
            • Rich Text Editor Styles
            • Rich Text Editor Plugins
            • Blocks in Rich Text Editor
      • Login
      • Document Blueprints
      • Sidebar
      • Log Viewer
      • Language Variants
      • Settings Dashboards
    • Data
      • Defining Content
        • Default Document Types
        • Document Type Localization
      • Creating Media
        • Default Data/Media Types
      • Members
      • Data Types
        • Default Data Types
      • Scheduled Publishing
      • Using Tabs
      • Users
      • Relations
      • Dictionary Items
      • Content Version Cleanup
    • Design
      • Templates
        • Basic Razor Syntax
        • Razor Cheatsheet
      • Rendering Content
      • Rendering Media
      • Partial Views
      • Stylesheets And JavaScript
    • Code
      • Service APIs
      • Subscribing To Notifications
      • Creating Forms
      • Debugging
        • Logging
      • Source Control
  • Implementation
    • Learn how Umbraco works
    • Routing
      • Controller & Action Selection
      • Execute Request
      • Request Pipeline
    • Custom Routing
      • Adding a hub with SignalR and Umbraco
    • Controllers
    • Data Persistence (CRUD)
    • Composing
    • Integration Testing
    • Nullable Reference Types
    • Services and Helpers
      • Circular Dependencies
    • Unit Testing
  • Customizing
    • Extend and customize the editing experience
    • Project Bellissima
    • Setup Your Development Environment
      • Vite Package Setup
    • Foundation
      • Working with Data
        • Repositories
        • Context API
        • Store
        • States
      • Contexts
        • Property Dataset Context
      • Umbraco Element
        • Controllers
          • Write your own controller
      • Sorting
      • Routes
      • Icons
      • Backoffice Localization
      • Terminology
    • Extension Overview
      • Extension Registry
        • Extension Registration
        • Extension Manifest
      • Extension Types
        • Menu
        • Header Apps
        • Icons
        • Modals
          • Confirm Dialog
          • Custom Modals
          • Route Registration
        • Bundle
        • Kind
        • Backoffice Entry Point
        • Extension Conditions
        • Dashboards
        • Entity Actions
        • Entity Bulk Actions
        • Entity Create Option Action
        • Trees
        • Global Context
        • Section Sidebar
        • Section View
        • Sections
        • Workspace Context
        • Workspace Views
        • Workspace Actions
        • Localization
      • Extension Kind
      • Extension Conditions
      • Custom Extension types
    • Sections & Trees
    • Searchable Trees (ISearchableTree)
    • Property Editors
      • Property Editors Composition
        • Property Editor Schema
        • Property Editor UI
      • Property Value Converters
      • Property Actions
      • Integrate Property Editors
      • Tracking References
      • Content Picker Value Converter Example
      • Property Dataset
      • Integrate Validaction
    • Workspaces
    • Umbraco Package
    • UI Library
  • Extending
    • Build on Umbraco functionality
    • Health Check
      • Health Check Guides
        • Click-Jacking Protection
        • Content Content Security Policy (CSP)
        • Content/MIME Sniffing Protection
        • Cross-site scripting Protection (X-XSS-Protection header)
        • Debug Compilation Mode
        • Excessive Headers
        • Fixed Application Url
        • Folder & File Permissions
        • HTTPS Configuration
        • Notification Email Settings
        • SMTP
        • Strict-Transport-Security Header
    • Language Files & Localization
      • .NET Localization
    • Backoffice Search
    • Creating a Custom Database Table
    • Embedded Media Providers
    • Custom File Systems (IFileSystem)
      • Using Azure Blob Storage for Media and ImageSharp Cache
    • Configuring Azure Key Vault
    • Packages
      • Creating a Package
      • Language file for packages
      • Listing a Package on the Umbraco Marketplace
      • Good practice and defaults
      • Packages on Umbraco Cloud
      • Installing and Uninstalling Packages
      • Maintaining packages
      • Create accessible Umbraco packages
      • Example Package Repository
  • Reference
    • Dive into the code
    • Configuration
      • Basic Authentication Settings
      • Connection strings settings
      • Content Dashboard Settings
      • Content Settings
      • Data Types Settings
      • Debug settings
      • Examine settings
      • Exception filter settings
      • FileSystemProviders Configuration
      • Global Settings
      • Health checks
      • Hosting settings
      • Imaging settings
      • Indexing settings
      • Install Default Data Settings
      • Logging settings
      • Maximum Upload Size Settings
      • Models builder settings
      • NuCache Settings
      • Package Migration
      • Plugins settings
      • Request handler settings
      • Runtime settings
      • Security Settings
      • Serilog settings
      • Type finder settings
      • Unattended
      • Web routing
    • Templating
      • Models Builder
        • Introduction
        • Configuration
        • Builder Modes
        • Understand and Extend
        • Using Interfaces
        • Tips and Tricks
      • Working with MVC
        • Working with MVC Views in Umbraco
        • View/Razor Examples
        • Using MVC Partial Views in Umbraco
        • Using View Components in Umbraco
        • Querying & Traversal
        • Creating Forms
      • Macros
    • Querying & Models
      • IMemberManager
      • IPublishedContentQuery
      • ITagQuery
      • UDI Identifiers
      • UmbracoContext helper
      • UmbracoHelper
      • IPublishedContent
        • IPublishedContent Collections
        • IPublishedContent IsHelpers
        • IPublishedContent Property Access & Extension Methods
    • Routing & Controllers
      • Custom MVC controllers (Umbraco Route Hijacking)
      • Custom MVC Routes
      • Custom Middleware
      • URL Rewrites in Umbraco
      • Special Property Type aliases for routing
      • URL Redirect Management
      • Routing in Umbraco
        • FindPublishedContentAndTemplate()
        • IContentFinder
        • Inbound request pipeline
        • Outbound request pipeline
        • Published Content Request Preparation
      • Surface controllers
        • Surface controller actions
      • Umbraco API Controllers
        • Porting old Umbraco API Controllers
    • Content Delivery API
      • Custom property editors support
      • Extension API for querying
      • Media Delivery API
      • Protected content in the Delivery API
      • Output caching
      • Property expansion and limiting
      • Additional preview environments support
    • Webhooks
      • Expanding Webhook Events
    • API versioning and OpenAPI
    • Searching
      • Examine
        • Examine Management
        • Examine Manager
        • Custom indexing
        • PDF indexes and multisearchers
        • Quick-start
    • Using Notifications
      • Notification Handler
      • CacheRefresher Notifications Example
      • ContentService Notifications Example
      • Creating And Publishing Notifications
      • Determining if an entity is new
      • MediaService Notifications Example
      • MemberService Notifications Example
      • Sending Allowed Children Notification
      • Umbraco Application Lifetime Notifications
      • EditorModel Notifications
        • Customizing the "Links" box
      • Hot vs. cold restarts
    • Inversion of Control / Dependency injection
    • Management
      • Using Umbraco services
        • Consent Service
        • Media Service
        • Relation Service
        • Content Service
        • Content Type Service
        • Localization Service
        • User Service
    • Plugins
      • Creating Resolvers
      • Finding types
    • Cache & Distributed Cache
      • Accessing the cache
      • ICacheRefresher
      • IServerMessenger
      • Getting/Adding/Updating/Inserting Into Cache
      • Examples
        • Working with caching
    • Response Caching
    • Security
      • API rate limiting
      • BackOfficeUserManager and Events
      • Cookies
      • Replacing the basic username/password check
      • External login providers
      • Locking of Users and password reset
      • Reset admin password
      • Umbraco Security Hardening
      • Umbraco Security Settings
      • Sensitive data
      • Sanitizing the Rich Text Editor
      • Setup Umbraco for a FIPS Compliant Server
      • HTTPS
      • Two-factor Authentication
      • Server-side file validation
    • Scheduling
    • Common Pitfalls & Anti-Patterns
    • API Documentation
    • Debugging with SourceLink
    • Language Variation
    • UmbracoMapper
    • Distributed Locks
    • Management API
      • Setup OAuth using Postman
    • Custom Swagger API
    • Umbraco Flavored Markdown
  • Tutorials
    • Overview
    • Creating a Basic Website
      • Getting Started
      • Document Types
      • Creating Your First Template
      • CSS and Images
      • Displaying the Document Type Properties
      • Creating a Master Template
      • Creating Pages and Using the Master Template
      • Setting the Navigation Menu
      • Articles and Article Items
      • Adding Language Variants
      • Conclusions
    • Creating your First Extension
    • Creating a Custom Dashboard
      • Adding localization to the dashboard
      • Adding functionality to the Dashboard
      • Using Umbraco UI library in the Dashboard
    • Creating a Property Editor
      • Adding configuration to a Property Editor
      • Integrating context with a Property Editor
      • Custom value conversion for rendering
      • Adding server-side validation
        • Default Property Editor Schema aliases
    • Creating a Multilingual Site
    • Add Google Authentication (Users)
    • Add Microsoft Entra ID authentication (Members)
    • Creating Custom Database Tables with Entity Framework
    • The Starter Kit
      • Lessons
        • Customize the Starter Kit
        • Add a Blog Post Publication Date
          • Add a Blog Post Publication Date
          • Add a Blog Post Publication Date
        • Add Open Graph
          • Add Open Graph - Step 1
          • Add Open Graph - Step 2
          • Add Open Graph - Step 3
          • Add Open Graph - Step 4
          • Add Open Graph - Summary
        • Ask For Help and Join the Community
    • Editor's Manual
      • Getting Started
        • Logging In and Out
        • Umbraco Interface
        • Creating, Saving and Publishing Content Options
        • Finding Content
        • Editing Existing Content
        • Sorting Pages
        • Moving a Page
        • Copying a Page
        • Deleting and Restoring Pages
      • Working with Rich Text Editor
      • Version Management
        • Comparing Versions
        • Rollback to a Previous Version
      • Media Management
        • Working with Folders
        • Working with Media Types
        • Cropping Images
      • Tips & Tricks
        • Refreshing the Tree View
        • Audit Trail
        • Notifications
        • Preview Pane Responsive View
        • Session Timeout
    • Multisite Setup
    • Member Registration and Login
    • Custom Views for Block List
    • Connecting Umbraco Forms and Zapier
    • Creating an XML Sitemap
    • Implement Custom Error Pages
    • Create a custom maintenance page
    • Creating a backoffice API
      • Documenting your controllers
      • Adding a custom Swagger document
      • Versioning your API
      • Polymorphic output in the Management API
      • Umbraco schema and operation IDs
      • Access policies
Powered by GitBook
On this page
  • Models Generation Process
  • Composition and Inheritance
  • Composition
  • Inheritance
  • Extending Models
  • Custom Model Generation with IModelsGenerator
  • Best Practices for Extending Models
  • Good practices
  • Bad practices
  • Ugly practices
Edit on GitHub
Export as PDF
  1. Reference
  2. Templating
  3. Models Builder

Understand and Extend

Understanding and Extending ModelsBuilder in Umbraco

Umbraco’s Models Builder automatically generates strongly typed models for content types, allowing developers to work with Umbraco data in a structured and efficient manner. This article explains how models are generated, how composition and inheritance work, and best practices for extending models without causing issues.

Models Generation Process

Models Builder generates each content type as a partial class. For example, a content type named TextPage results in a TextPage.generated.cs file with a structure like this:

/// <summary>TextPage</summary>
[PublishedModel("textPage")]
public partial class TextPage : PublishedContentModel
{
  //static helpers
  public new const string ModelTypeAlias = "textPage";

  public new const PublishedItemType ModelItemType = PublishedItemType.Content;

  public new static IPublishedContentType GetModelContentType(IPublishedSnapshotAccessor publishedSnapshotAccessor)
    => PublishedModelUtility.GetModelContentType(publishedSnapshotAccessor, ModelItemType, ModelTypeAlias);

  public static IPublishedPropertyType GetModelPropertyType<TValue>(IPublishedSnapshotAccessor publishedSnapshotAccessor, Expression<Func<TextPage, TValue>> selector)
    => PublishedModelUtility.GetModelPropertyType(GetModelContentType(publishedSnapshotAccessor), selector);

  private IPublishedValueFallback _publishedValueFallback;

  //constructor
  public TextPage(IPublishedContent content, IPublishedValueFallback publishedValueFallback)
    : base(content, publishedValueFallback)
  {
    _publishedValueFallback = publishedValueFallback;
  }

  // properties

  ///<summary>
  /// Header
  ///</summary>
  [ImplementPropertyType("header")]
  public virtual string Header => this.Value<string>(_publishedValueFallback, "header");
}

In the above code:

  • The model includes a constructor and static helpers to fetch the content type (PublishedContentType) and property type (PublishedPropertyType).

  • The most important part is the property definition (Header), which retrieve values from Umbraco.

You can use helper methods to access content and property types:

var contentType = TextPage.GetModelContentType(); // is a PublishedContentType
var propertyType = TextPage.GetModelPropertyType(x => x.Header); // is a PublishedPropertyType

Composition and Inheritance

Composition

Umbraco content types can be composed of multiple other content types. Unlike traditional C# inheritance, Umbraco allows a content type to inherit properties from multiple sources.

In Umbraco v14, the traditional .NET Inheritance feature has been removed. Instead, properties are inherited through Composition, allowing for greater flexibility in managing content types.

For example, a TextPage might be composed of:

  • MetaInfo content type (inherits Author and Keywords properties).

  • PageInfo content type (inherits Title and MainImage properties).

Each content type involved in a composition is generated both as a class and as an interface. The MetaInfo content type would be generated as:

// The composition interface
public partial interface IMetaInfo : IPublishedContent
{
  public string Author { get; }
  public IEnumerable<string> Keywords { get; }
}

// The composition class
public partial class MetaInfo : PublishedContentModel
{
  // the "static mixin getter" for the property
  public static string GetAuthor(IMetaInfo that)
  {
    return that.GetPropertyValue<string>("author");
  }

  public string Author { get { return MetaInfo.GetAuthor(this, _publishedValueFallback); } }
}

And the TextPage model would be generated as:

public partial class TextPage : PublishedContentModel, IMetaInfo
{
  // get the property value from the "static mixin getter"
  public string Author { get { return MetaInfo.GetAuthor(this, _publishedValueFallback); } }
}

Inheritance

In addition to composition, content types can have a parent-child relationship. In the Umbraco backoffice, a content type appears underneath its parent.

By convention, a content type is always composed of its parent and therefore inherits its properties. However, the parent content type is treated differently, and the child content type directly inherits (as in C# inheritance) from the parent class.

If AboutPage is a child of TextPage, its generated model would inherit directly from TextPage:

// Note: Inherits from TextPage
public partial class AboutPage : TextPage
{
  ...
}

Extending Models

Since models are partial classes, developers can extend them by adding additional properties.

For Example:

public partial class TextPage
{
    public string WrappedHeader => $"[{Header}]";
}

Models Builder does not recognize custom partial classes during regeneration. If your custom class conflicts with the generated class (e.g., overriding a constructor), it will cause compilation errors.

Overloaded constructors will not be used because models are always instantiated using the default constructor.

Custom Model Generation with IModelsGenerator

From Umbraco 11.4, you can implement the IModelsGenerator interface hto customize how models are generated. This allows you to replace Umbraco’s default implementation using dependency injection:

The interface can be accessed via Infrastructure.ModelsBuilder.Building.ModelsGenerator.

Best Practices for Extending Models

Extending models should be used to add stateless, local features to models. It should not be used to transform content models into view models or manage trees of content.

Good practices

A customer has "posts" that has two "release date" properties. One is a true date picker property and is used to specify an actual date and to order the posts. The other is a string that is used to specify dates such as "Summer 2015" or "Q1 2016". Alongside the title of the post, the customer wants to display the text date, if present, else the actual date. If none of those are present, the Umbraco update date should be used. Keep in mind that each view can contain code to deal with the situation, but it is much more efficient to extend the Post model:

    public partial class Post
    {
        public string DisplayDate
        {
            get
            {
                if(!TextDate.IsNullOrWhiteSpace())
                {
                    return TextDate;
                }

                if (ActualDate != default)
                {
                    return ActualDate.ToString();
                }

                return UpdateDate.ToString();
            }
        }
    }

Simplified view:

<div class="title">
  <div class="title-text">@Model.Title</div>
  <div class="title-date">@Model.DisplayDate</div>
</div>

Bad practices

Because, by default, the content object is passed to views, one can be tempted to add view-related properties to the model. Some properties that do not belong to a content model would be:

  • A HomePage property that retrieves the "home page" content item.

  • A Menu property that lists navigation items.

Generally speaking, anything that is tied to the current request, or that depends on more than the modeled content, is a bad idea. There are much cleaner solutions, such as using true view model classes that would be populated by a true controller and look like:

public class TextPageViewModel
{
  public TextPage Content; // The content model
  public HomePage HomePage; // The home page content model
  public IEnumerable<MenuItem> Menu; // The menu content models
}

One can also extend Umbraco's views to provide a special view helper that gives access to important elements of the website:

<a href="@MySite.HomePage.Url">@MySite.HomePage.Title</a>

Ugly practices

The model's scope and lifecycle are unspecified. It may exist only for your request or be cached and shared across all requests.

The code has a major issue: the TextPage model caches a HomePageDocument model that will not update when the home page is re-published.

private HomePageDocument _homePage;
public HomePageDocument HomePage
{
    get
    {
        if (_homePage is null)
        {
            _homePage = this.AncestorOrSelf<HomePageDocument>(1);
        }
        return _homePage;
    }
}

As a rule of thumb, models should never reference and cache other models.

PreviousBuilder ModesNextUsing Interfaces

Last updated 3 months ago

For more complex customizations, use the full version of .

Models Builder