Issues

Working with Content Types and Data Types Programmatically

The Umbraco backoffice is great for managing things like content types and data types. Using the backoffice is both user friendly and Umbraco will ensure that everything is saved correctly.

But as a developer, we'd sometimes need to create or manage content types and data types programmatically, which can be a bit tricky to get all the different parts right - especially since not all of this is documented.

This article will walk through the steps to create or update an content type, as well as provide examples on how to create new data types using many of Umbraco's build-in property editors.

Programmatically creating and editing content and media are generally well documented, so I won't focus much on this for this article. But working with media and medias is not super well documented, so the article therefore finishes off with a few examples on this as well.

Content Types

Umbraco contains an IContentTypeService interface for working with content types through your own code. You can inject the interface in your class constructor or using @inject in a Razor view.

@using Umbraco.Cms.Core.Services
@inherits UmbracoViewPage

@inject IContentTypeService ContentTypeService

You can then use ContentTypeService to access the injected IContentTypeService.

Creating a new content type

To get started creating a simple content type, you can create a new instance of Umbraco's ContentType class. Genererally content types are represented by the IContentType interface, but when creating a new content type, we have to use the ContentType class directly (the class implements the IContentType interface.

The ContentType constructor takes an instance of IShortStringHelper, and then the numeric parent ID of where in the content type tree the new content type should be located.

Umbraco internally uses the IShortStringHelper service to convert names to safe aliases. The implementation of this service isn't all that important for this article, so I won't go in detail about it. You can inject it via @inject IShortStringHelper ShortStringHelper and then pass in on to the constructor via it's first parameter.

The second parameter is the parent ID. If you wish to create your content type under a specific folder in the content type tree, you can set this parameter to the parent's ID. To create your content type in the root of the content type tree, you can pass on -1 instead.

@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Strings

@inherits UmbracoViewPage

@inject IShortStringHelper ShortStringHelper
@inject IContentTypeService ContentTypeService

@{

    // Create a new content type in memory
    ContentType contentType = new ContentType(ShortStringHelper, -1)
    {
        Alias = "settingsComp",
        Name = "Settings",
        Icon = "icon-defrag"
    };

    // Save the content type
    ContentTypeService.Save(contentType);

}

Adding a property group

The example above only creates the content type, but we haven't added any properties to it yet. In order to add properties, we should first add one or more property groups.

A property group represents either a tab or a property group under a tab. A property group is shown under a tab, but in code, tabs and groups are represented by a flat collection of PropertyGroup.

A new tab or property can be added like shown as below:

// Initialize a "Settings" tab
var settingsTab = new PropertyGroup(new PropertyTypeCollection(contentType.SupportsPublishing))
{
    Alias = "settings",
    Name = "Settings",
    Type = PropertyGroupType.Tab,
    SortOrder = 100
};

// Add a new tab to the content type
contentType.PropertyGroups.Add(settingsTab);

And a property group such as:

// Initialize a "Settings" tab
var seoGroup = new PropertyGroup(new PropertyTypeCollection(contentType.SupportsPublishing))
{
    Alias = "settings/seo",
    Name = "SEO",
    Type = PropertyGroupType.Info
};

// Add a new tab to the content type
contentType.PropertyGroups.Add(settingsTab);

Notice the group alias. A group with the alias seo will be created under a Generic tab, whereas a group with the alias settings/seo will be created under the tab with the alias settings.

Adding a property type

A property of a content type is referred to a property type, and as such represented by the PropertyType class.

// Add a new property type to the "Settings" tab
propertyGroup.PropertyTypes!.Add(new PropertyType(ShortStringHelper, trueFalse)
{
    Alias = "umbracoNaviHide",
    Name = "Hide from navigation?",
    Description = "Select whether the page should be hidden from navigation."
});

Similar to when creating a content type, the PropertyType's first constructor should be an instance of IShortStringHelper. The second parameter is an instance of IDateType. In this case, trueFalse refers to Umbraco's True/false data type.

Adding content type compositions

A content type is made up of property groups and property types added directly to the content type, and then property groups and property types added to one or more composition types the content type is using.

In code, content type compositions can be added via the ContentTypeComposition property:

// Get a reference to our "Settings" composition type
IContentType? settingsComposition = ContentTypeService.Get("settingsComp");
if (settingsComposition is null) throw new Exception("Oh noes!");

// Set the new content type's compositions
contentType.ContentTypeComposition = new List
{
    settingsComposition
};

Notice that the ContentTypeComposition property is of the type IEnumerable<IContentTypeComposition>. As we're in the process of creating a new content type, we can simply replace the existing with a new List<IContentTypeComposition>. If editing an existing content type, you should take existing composition types into account.

 Creating a settings content type composition

The full example for creating a Settings composition type is illustrated with the snippet below:

@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Strings

@inherits UmbracoViewPage

@inject IShortStringHelper ShortStringHelper
@inject IContentTypeService ContentTypeService
@inject IDataTypeService DataTypeService

@{

    // Gets a reference to Umbraco's default "True/false" data type
    IDataType? trueFalse = DataTypeService.GetDataType(-49);
    if (trueFalse is null) throw new Exception("Oh noes!");

    // Create a new content type in memory
    ContentType contentType = new ContentType(ShortStringHelper, -1)
    {
        Alias = "settingsComp",
        Name = "Settings",
        Icon = "icon-defrag",
        IsElement = true
    };

    // Initialize a new property group
    var propertyGroup = new PropertyGroup(new PropertyTypeCollection(contentType.SupportsPublishing))
    {
        Alias = "settings",
        Name = "Settings",
        Type = PropertyGroupType.Tab,
        SortOrder = 100
    };

    // Add a new property type to the "Settings" tab
    propertyGroup.PropertyTypes!.Add(new PropertyType(ShortStringHelper, trueFalse)
    {
        Alias = "umbracoNaviHide",
        Name = "Hide from navigation?",
        Description = "Select whether the page should be hidden from navigation."
    });

    // Add a new tab to the content type
    contentType.PropertyGroups.Add(propertyGroup);

    // Save the content type
    ContentTypeService.Save(contentType);

    <pre>@contentType.Id</pre>
    <pre>@contentType.Key</pre>

}

When creating a new Composition via Umbraco's UI, it's marked as an element type by default. Whether this should be the case might be a bit debateable. If a composition type is only used by non-element types, I'd argue that the composition shouldn't be an element type either.

This may not matter that much, but when using ModelsBuilder, it determines whether the generated model for the composition inherits from IPublishedContent or IPublishedElement.

Creating a contentPage content type

The example belows illistrates a Content Page content type, which would represent a basic page - eg. using Umbraco's block list for the content. Such a page would likely share a few setting with other page types, so it uses the above settingsComp composition while also having the title and teaser properties on it's own.

The title and teaser properties are added to a Intro property group, which is again added to a Content tab.

@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Strings

@inherits UmbracoViewPage

@inject IShortStringHelper ShortStringHelper
@inject IContentTypeService ContentTypeService
@inject IDataTypeService DataTypeService


@{

    // Gets a reference to Umbraco's default "Textstring" data type
    IDataType? textstring = DataTypeService.GetDataType(-88);
    if (textstring is null) throw new Exception("Oh noes!");

    // Gets a reference to Umbraco's default "Textarea" data type
    IDataType? textarea = DataTypeService.GetDataType(-89);
    if (textarea is null) throw new Exception("Oh noes!");

    // Get a reference to our "Settings" composition type
    IContentType? settingsComposition = ContentTypeService.Get("settingsComp");
    if (settingsComposition is null) throw new Exception("Oh noes!");

    // Create a new content type in memory
    ContentType contentType = new ContentType(ShortStringHelper, -1)
    {
        Alias = "contentPage",
        Name = "Content Page",
        Icon = "icon-document"
    };

    // Set the new content type's compositions
    contentType.ContentTypeComposition = new List<IContentTypeComposition>
    {
        settingsComposition
    };

    // Initialize a new "Content" tab
    var contentPropertyGroup = new PropertyGroup(new PropertyTypeCollection(false))
    {
        Alias = "content",
        Name = "Content",
        Type = PropertyGroupType.Tab
    };

    // Initialize a new "Intro" group
    var introPropertyGroup = new PropertyGroup(new PropertyTypeCollection(false))
    {
        Alias = contentPropertyGroup.Alias + "/intro",
        Name = "Intro",
        Type = PropertyGroupType.Group,
        
    };

    // Add a new "Title" property type to the "Settings" tab
    introPropertyGroup.PropertyTypes!.Add(new PropertyType(ShortStringHelper, textstring)
    {
        Alias = "title",
        Name = "Title",
        Description = "The title of the page."
    });

    // Add a new "Description" property type to the "Settings" tab
    introPropertyGroup.PropertyTypes!.Add(new PropertyType(ShortStringHelper, textstring)
    {
        Alias = "teaser",
        Name = "Teaser",
        Description = "The teaser of the page."
    });

    // Append the "Content" tab to the content type
    contentType.PropertyGroups.Add(contentPropertyGroup);

    // Append the "Intro" group to the content type
    contentType.PropertyGroups.Add(introPropertyGroup);
 
    // Save and persist the content type to the database
    ContentTypeService.Save(contentType);

    <pre>@contentType.Id</pre>
    <pre>@contentType.Key</pre>

}

 

Property Editors

When working with data types, it's also relevant to talk about property editors. A data type is based on a property editor, and multiple data types may be using the same property editor. But a property editor may also exist without any data types using it.

Programmatically property editors can be accessed via the PropertyEditorCollection class in the Umbraco.Cms.Core.PropertyEditors namespace. The class represents a collection of all the property editors registered in your Umbraco installation.

The class has an indexer property, so if you are looking for a particular property editor, you can get the property as shown below:

@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core
@inject PropertyEditorCollection PropertyEditors

@{

    IDataEditor? editor = PropertyEditors[Constants.PropertyEditors.Aliases.TextBox];

}

Or you can use the TryGet method instead:

@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core
@inject PropertyEditorCollection PropertyEditors

@{

    if (!PropertyEditors.TryGet(Constants.PropertyEditors.Aliases.TextBox, out IDataEditor? editor)) {
        <div>Computer says no!</div>
        return;
    }

}

Notice that Umbraco has constants for the aliases of all the build-in property editors.

Value Editor

A property editor declares a value editor, which represents what the users see for properties of a given property editor. For one, a value editor specifies the a value type - which determines how the value editor's value is saved to the database. This is relevant when creating a new data type.

Getting the value type programmatically could look like:

@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core
@inject PropertyEditorCollection PropertyEditors

@{

    // Try to get a reference to the "Umbraco.TextBox" property editor
    if (!PropertyEditors.TryGet(Constants.PropertyEditors.Aliases.TextBox, out IDataEditor? editor)) {
        <div>Computer says no!</div>
        return;
    }

    // Get the value editor for the property editor
    var valueEditor = editor.GetValueEditor();

    // Write out the value type
    <pre>@valueEditor.ValueType</pre>

}

In this case, the textbox property editor has the value type STRING. Also, here we're calling the parameterless GetValueEditor method. Most property editors have the same value type regardless of the configuration, but the method has an overload with a parameter representing a configuration object.

Data Types

Data types can be accessed by injecting the IDataTypeService interface. Individual data types are represented by the IDataTye interface, and specifically the DataType class. Normally you'd only need to work with data types via the interface, but when creating a new data type, you need to use the class directly.

Database Type

Each data type specifies how property values using the given data type should be saved in the database. The database type is based on the property editor's value type, although the two doesn't represent exactly the same.

Umbraco uses the ValueStorageType enum class for representing the supported database types. And the ValueTypes class features a static ToStorageType method for converting the property editor's value type to a ValueStorageType :

// Get the default database type
ValueStorageType databaseType = ValueTypes
    .ToStorageType(editor.GetValueEditor().ValueType);

Creating a new data type

New data types can be created via the DataType class' constructor. This will not persist the data type to the database, but it lets us further modify the data type in C#, and then save the data type via IDataTypeService's Save method:

<code@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.Serialization
@using Umbraco.Cms.Core.Services

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == "myEditor");

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId);

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

}

The first parameter for the constructor is an instance of IDataEditor with the property editor that should be used for the data type. The second parameter should be an instance of IConfigurationEditorJsonSerializer - which you can inject as shown in the example above. The third parameter is optional, and if specified, should be the numeric ID of the folder in which the data type should be created. If not specified, the data type is created at the root of the data type tree.

Before saving the data type, you should ideally also set some on the other properties of the IDataType instance - in particular the NameDatabaseType and Configuration properties.

Creating a new checkbox list data type

The Checkbox list property editor (alias: Umbraco.CheckBoxList) let's users select between a pre-defined list of items configured for each data type using this property editor.

The data type configuration is represented by the ValueListConfiguration class, which let's you define the items that should be available in the value editor. Each item is represented by the ValueListConfiguration.ValueListItem nested class.

What value you set for the ID of each item is not really super important, although they have to be unique within the data type. Umbraco's seems to be using forthcoming numbers, so the example below follows this approach.

@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization

@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.CheckBoxList);

    // Initialize the configuration object
    ValueListConfiguration config = new ValueListConfiguration {
        Items = new List<ValueListConfiguration.ValueListItem> {
            new ValueListConfiguration.ValueListItem {
                Id = 1,
                Value = "Hello World"
            },
            new ValueListConfiguration.ValueListItem {
                Id = 2,
                Value = "Hej Verden"
            }
        }
    };

    // Get the database type for "editor" and "config"
    ValueStorageType databaseType = ValueTypes
        .ToStorageType(editor.GetValueEditor(config).ValueType);

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "My checkbox list",
        DatabaseType = databaseType,
        Configuration = config
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new color picker data type

The Color Picker property editor (alias: Umbraco.ColorPicker) let's users select between a list of pre-defined colors configured through the data type options.

The data type configuration is represented by the ColorPickerConfiguration class. The class features an Items property that you can use to configure the available colors/items. Each item (color) is represented by the ValueListConfiguration.ValueListItem nested class.

Notice that the Value for each item should be a JSON object with both the value (HEX value) and name (label) of the item.

@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.Serialization
@using Umbraco.Cms.Core
@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditorCollection
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor colorPicker = PropertyEditorCollection
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.ColorPicker);

    // Initialize the configuration object
    ColorPickerConfiguration config = new ColorPickerConfiguration {
        UseLabel = true,
        Items = new List<ValueListConfiguration.ValueListItem> {
            new ValueListConfiguration.ValueListItem {
                Id = 1,
                Value = "{\"value\":\"ed1212\",name:\"Red\"}"
            },
            new ValueListConfiguration.ValueListItem {
                Id = 2,
                Value = "{\"value\":\"8fce00\",name:\"Green\"}"
            }
        }
    };

    // Get the database type for "editor" and "config"
    ValueStorageType databaseType = ValueTypes
        .ToStorageType(colorPicker.GetValueEditor(config).ValueType);

    // Initialize a new data type
    IDataType dataType = new DataType(colorPicker, ConfigurationEditorJsonSerializer, parentId) {
        Name = "My color picker",
        DatabaseType = databaseType,
        Configuration = config
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new content picker data type

The Content Picker property editor (alias: Umbraco.ContentPicker) let's users select a single content node. The data type can be configured to control what content nodes users will be able to select.

The data type configuration is represented by the ContentPickerConfiguration class. Like when editing a content picker data type in the backoffice, it has a few different options - all of them being optional.

@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization
@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.ContentPicker);

    // Initialize the configuration
    ContentPickerConfiguration config = new ContentPickerConfiguration {
        ShowOpenButton = false,
        StartNodeId = new GuidUdi("document", new Guid("db25f0d0-f80f-4262-b279-c2e6568b325a")),
        IgnoreUserStartNodes = false
    };

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "My content picker",
        Configuration = config,
        DatabaseType = ValueTypes.ToStorageType(editor.GetValueEditor(config).ValueType)
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new date time data type

The Date/Time property editor (alias: Umbraco.DateTime) let's user select a point in time consisting of both a date and time.

The data type configuration is represented by the DateTimeConfiguration class. For one, it let's you set the format being used by the value editor.

@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization
@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

   // Get ID of the folder in which the new data type will be created
   int parentId = 1122;

   // Get a reference to the property editor
   IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.DateTime);

    // Get the default database type
    ValueStorageType databaseType = ValueTypes
        .ToStorageType(editor.GetValueEditor(null).ValueType);

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "My DateTime",
        DatabaseType = databaseType
    };

    // Set the configuration
    dataType.Configuration = new DateTimeConfiguration {
        Format = "YYYY-MM-DD HH:mm:ss",
        OffsetTime = false
    };

    // Set the database type
    dataType.DatabaseType = ValueTypes
        .ToStorageType(editor.GetValueEditor(dataType.Configuration).ValueType);

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new decimal type

The data type for the Decimal property editor (alias: Umbraco.Decimal) doesn't have it's own configuration class, so it instead relies on a Dictionary<string, object> instance instead. You may add values for min, step and max, but all of them are optional.

@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization
@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.Decimal);

    // Initialize the configuration
    var config = new Dictionary<string, object> {
        {"min", -1},
        {"step", 1},
        {"max", 10}
    };

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "My decimal",
        Configuration = config,
        DatabaseType = ValueTypes.ToStorageType(editor.GetValueEditor(config).ValueType)
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new dropdown list data type

The Dropdown property editor (alias: Umbraco.DropDown.Flexible) let's users select between a list of pre-defined items configured in the data type.

The configuration is represented by the DropDownFlexibleConfiguration class, and similar to other item based data types, each item is represented by the ValueListConfiguration.ValueListItem nested class.

@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization

@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.DropDownListFlexible);

    // Initialize the configuration
    var config = new DropDownFlexibleConfiguration {
        Multiple = false,
        Items = new List<ValueListConfiguration.ValueListItem> {
            new ValueListConfiguration.ValueListItem {
                Id = 1,
                Value = "Hello World"
            },
            new ValueListConfiguration.ValueListItem {
                Id = 2,
                Value = "Hej Verden"
            }
        }
    };

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "My dropdown list",
        Configuration = config,
        DatabaseType = ValueTypes.ToStorageType(editor.GetValueEditor(config).ValueType)
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new eye dropper data type

The Eye Dropper Color Picker property editor (alias: Umbraco.ColorPicker.EyeDropper) let's users select a single RGB color.

Thedata type's configuration is represented by the EyeDropperColorPickerConfiguration class. For one, you may set the ShowAlpha property to true to allow alpha values.

@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization

@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.ColorPickerEyeDropper);

    // Initialize the configuration
    var config = new EyeDropperColorPickerConfiguration {
        ShowAlpha = true,
        ShowPalette = true
    };

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "Eye Dropper",
        Configuration = config,
        DatabaseType = ValueTypes.ToStorageType(editor.GetValueEditor(config).ValueType)
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new file upload data type

The File upload property editor let's user upload a file to a property rather than in the media archive. The data type's configuration is represented by the FileExtensionConfigItem class, which allows you to configure the accepted file extensions via the FileExtensions property.

@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization

@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.UploadField);

    // Initialize the configuration
    var config = new FileUploadConfiguration {
        FileExtensions = new List<FileExtensionConfigItem> {
            new FileExtensionConfigItem {
                Id = 1, // Umbraco always set the IDs to zero (0)
                Value = "cs"
            },
            new FileExtensionConfigItem {
                Id = 2,
                Value = "cshtml"
            }
        }
    };

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "Upload Field",
        Configuration = config,
        DatabaseType = ValueTypes.ToStorageType(editor.GetValueEditor(config).ValueType)
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a label data type

The Label property editor (alias: Umbraco.Label) may be used to store readonly data that users are not supposed to edit. The data type configuration is represented by the LabelConfiguration class, it let's you configure which value type will be used when storing property values using this data type in the database.

In the example below, I'm creating a new Label data type with the value type ValueTypes.Text (constant with the value TEXT).

@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization
@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.Label);

    // Initialize the configuration
    LabelConfiguration config = new LabelConfiguration {
        ValueType = ValueTypes.Text
    };

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "My label",
        Configuration = config,
        DatabaseType = ValueTypes.ToStorageType(editor.GetValueEditor(config).ValueType)
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new member group picker data type

The Member Group Picker property editor (alias: Umbraco.MemberGroupPicker) doesn't have any configuration, so in the example below, I'm passing null to the editor.GetValueEditor method.

@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization
@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.MemberGroupPicker);

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "My member group picker",
        DatabaseType = ValueTypes.ToStorageType(editor.GetValueEditor(null).ValueType)
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new member picker data type

The Member Picker property editor (alias: Umbraco.MemberPicker) works very similar to Umbraco.MemberGroupPicker as shown above. This property editor also doesn't have any configuration:

@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization
@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.MemberPicker);

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "My member picker",
        DatabaseType = ValueTypes.ToStorageType(editor.GetValueEditor(null).ValueType)
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new multi URL picker data type

The Multi URL Picker property editor (alias: Umbraco.MultiUrlPicker) let's users add either a single or a list of URL items. The configuration for data types created using this property editor is represented by the MultiUrlPickerConfiguration class, and it allows you to configure the following properties:

  • Minimum number of items (MinNumber)
    Indicates the minimum amount of allowed items. Default is 0.

  • Maximum number of items (MaxNumber)
    Indicates the maximum amount of allowed items. Default is 0 (no limit).

  • Overlay Size (OverlaySize)
    Sets the size of the link picker overlay. When creating or editing the data type through the backoffice, possible values are Small (small), Medium (medium) and Large (large). Default is small.

  • Hide anchor/query string input (HideAnchor)
    Indicates whether the anchor/query string field of the link picker overlay should be hidden. Default is false.

  • Ignore user start nodes (IgnoreUserStartNodes)
    Indicates whether the link picker overlay should ignore the user's permissions (start nodes). Default is false.

@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization
@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.MultiUrlPicker);

    // Initialize the configuration
    MultiUrlPickerConfiguration config = new MultiUrlPickerConfiguration {
        MinNumber = 1,
        MaxNumber = 10,
        OverlaySize = "medium",
        HideAnchor = true,
        IgnoreUserStartNodes = true
    };

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "My Multi URL Picker",
        Configuration = config,
        DatabaseType = ValueTypes.ToStorageType(editor.GetValueEditor(config).ValueType)
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new numeric data type

The Numeric (alias: Umbraco.Integer) property editor allows creating data types for specifying a single number (integer). Data types using this property editor have the following options:

  • Minimum (min)
    Indicates the minimum allowed value.

  • Step Size (step)
    Indicates the interval amount between each step of number to be entered.

  • Maximum (max)
    Indicates the maximum allowed value.

The configuration is represented by an Dictionary<string, object> instance. None of the properties have a default value, as options left blank are simply ommitted in the dictionary.

@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization
@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.Integer);

    // Initialize the configuration
    Dictionary<string, object> config = new Dictionary<string, object> {
        {"min", -10},
        {"step", 1},
        {"max", 10}
    };

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "My integer",
        Configuration = config,
        DatabaseType = ValueTypes.ToStorageType(editor.GetValueEditor(config).ValueType)
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new radio button list data type

Data types using the Radio button list property editor (alias: Umbraco.RadioButtonList) don't have any additional configuration besides being able to specify the available items.

The configuration is represented by the ValueListConfiguration class, and each item is represented by the ValueListConfiguration.ValueListItem nested class.

Each item of a ValueListConfiguration instance should have a unique numeric ID. When creating a new data type through the backoffice, the first item is assigned the ID 1, the second item 2 and so forth.

Paste@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization

@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.RadioButtonList);

    // Initialize the configuration object
    ValueListConfiguration config = new ValueListConfiguration {
        Items = new List<ValueListConfiguration.ValueListItem> {
            new ValueListConfiguration.ValueListItem {
                Id = 1,
                Value = "Hello World"
            },
            new ValueListConfiguration.ValueListItem {
                Id = 2,
                Value = "Hej Verden"
            }
        }
    };

    // Get the default database type
    ValueStorageType databaseType = ValueTypes
        .ToStorageType(editor.GetValueEditor(config).ValueType);

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "My radio button list",
        DatabaseType = databaseType,
        Configuration = config
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new multiple textstring data type

The configuration for data types using the Repeatable textstrings property editor (alias: Umbraco.MultipleTextstring) is represented by the MultipleTextStringConfiguration class, and it let's you configure both the minimum and maximum allowed amount of items through the Minimum and Maximum properties respectively.

@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization

@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.MultipleTextstring);

    // Initialize the configuration object
    MultipleTextStringConfiguration config = new MultipleTextStringConfiguration {
        Minimum = 0,
        Maximum = 10
    };

    // Get the default database type
    ValueStorageType databaseType = ValueTypes
        .ToStorageType(editor.GetValueEditor(config).ValueType);

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "My multiple textstring list",
        DatabaseType = databaseType,
        Configuration = config
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new rich text editor data type

Data types using the Rich Text Editor (alias: Umbraco.TinyMCE) propety editor use the RichTextConfiguration class for representing their configurations.

The class only has a handful of properties, while users are presented with a lot more options when creating or editing the data type in the backoffice. This is because the individual options for the underlying TinyMCE are presented to the user as individual options as well, while the TinyMCE options represented by the Editor property on RichTextConfiguration using a single JSON object.

As such, the data type has the following options:

  • Editor (alias: Editor)
    A JSON object representing the TinyMCE configuration.

    • Toolbar (alias: toolbar)
      The buttons that will be available in TinyMCE's toolbar. Possible values are:

      • Source Code Editor (ace)
      • Remove format (removeformat)
      • Undo (undo)
      • Redo (redo)
      • Cut (cut)
      • Copy (copy)
      • Paste (paste)
      • Style select (styleselect)
      • Bold (bold)
      • Italic (italic)
      • Underline (underline)
      • Strikethrough (strikethrough)
      • Justify left (alignleft)
      • Justify center (aligncenter)
      • Justify right (alignright)
      • Justify full (alignjustify)
      • Bullet list (bullist)
      • Numbered list (numlist)
      • Decrease indent (outdent)
      • Increase indent (indent)
      • Insert/edit link (link)
      • Remove link (unlink)
      • Anchor (anchor)
      • Image (umbmediapicker)
      • Macro (umbmacro)
      • Table (table)
      • Embed (umbembeddialog)
      • Horizontal rule (hr)
      • Subscript (subscript)
      • Superscript (superscript)
      • Character map (charmap)
      • Right to left (rtl)
      • Left to right (ltr)
  • Stylesheets (alias: stylesheets)
    The stylesheets that will be included for the Style select button.

  • Dimensions (alias: dimensions)
    The size of the rich text editor. May be omitted.

  • Maximum size for inserted images (alias: maxImageSize)
    Maximum width or height - enter 0 to disable resizing.

  • Mode (alias: mode)
    The mode of the editor. Possible values are classic and distraction-free. Default is classic.

  • Overlay Size (OverlaySize)
    Sets the size of the link picker overlay. When creating or editing the data type through the backoffice, possible values are Small (small), Medium (medium) and Large (large). Default is small.

  • Hide Label (alias: HideLabel)
    Whether the label and description of the property should be hidden.

  • Image Upload Folder (alias: MediaParentId)
    The UDI of the folder in which images uploaded through the RTE will be located, if specified.

  • Ignore user start nodes (alias: IgnoreUserStartNodes)
    Indicates whether the link picker overlay should ignore the user's permissions (start nodes). Default is false.

@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization
@using Newtonsoft.Json.Linq
@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.TinyMce);

    // Initialize the configuration for TinyMCE
    var tinyMceConfig = new JObject {
        {"toolbar", new JArray(
            "ace",
            "removeformat",
            "undo",
            "redo",
            "cut",
            "copy",
            "paste",
            "styleselect",
            "bold",
            "italic",
            "underline",
            "strikethrough",
            "alignleft",
            "aligncenter",
            "alignright",
            "alignjustify",
            "bullist",
            "numlist",
            "outdent",
            "indent",
            "link",
            "unlink",
            "anchor",
            "umbmediapicker",
            "umbmacro",
            "table",
            "umbembeddialog",
            "hr",
            "subscript",
            "superscript",
            "charmap",
            "rtl",
            "ltr"
        )},
        {"stylesheets", new JArray(
            "/css/dev/default.css"
        )},
        {"maxImageSize", 500},
        {"mode", "classic"},
        {"dimensions", new JObject {
            {"width", 500},
            {"height", 400}
        }}
    };

    // Initialize the data type configuration
    RichTextConfiguration config = new RichTextConfiguration {
        Editor = tinyMceConfig,
        OverlaySize = "medium",
        HideLabel = true,
        MediaParentId = new GuidUdi("media", new Guid("14497f2f-0ed4-435c-ad2c-084c3ad9feb0")),
        IgnoreUserStartNodes = true
    };

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId) {
        Name = "My RTE",
        Configuration = config,
        DatabaseType = ValueTypes.ToStorageType(editor.GetValueEditor(config).ValueType)
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

Creating a new block list data type

The configuration for data types using the Block List property editor (alias: Umbraco.BlockList) is represented by the BlockListConfiguration class, and it has the following properties:

  • Blocks
    The value of this property should be an array containing the configuration for the allowed blocks. Each block configuration is represented by the BlockListConfiguration.BlockConfiguration class.

  • ValidationLimit
    Describes the minimum and maximum allowed amount of block items. The value hsould be an instance of BlockListConfiguration.NumberRange, where the Min and Max properties can be used to control this further. If the Min property is set to null0 is used instead. If the Max property is set to null, no maximum limit is applied.

  • UseSingleBlockMode
    Indicates whether the block list should be in single mode or multi mode (default).

  • UseLiveEditing
    Indicates whether live editing should be enabled.

  • UseInlineEditingAsDefault
    Indicates whether inline editing should be enabled.

  • MaxPropertyWidth
    Indicates the maximum width of the block list property editor - eg. 800px or 100%.

Additionally, each block configuration (BlockListConfiguration.BlockConfiguration) has the following properties:

  • Label
    An optional label. The content type name is used as fallback if not specified.

  • View
    An optional custom view for previewing blocks of this type - eg. ~/App_Plugins/BlockList/Views/Quote.html.

  • Stylesheet
    A optional custom stylesheet - eg. ~/App_Plugins/BlockList/Styles.css.

  • EditorSize
    Indicates the size of the overlay that is opened when editing a block. Possible values are smallmedium and normal.

  • ContentElementTypeKey
    The GUID key of the content type that should be used for the content element. This must have a value.

  • SettingsElementTypeKey
    The GUID key of the content type that should be used for the settings element.

  • BackgroundColor
    An optional background color used for cards using this block configuration - eg. #000000.

  • IconColor
    An optional icon color used for cards using this block configuration - eg. #ffffff.

  • Thumbnail
    An optional thumbnail image that is used for cards using this block configuration - ~/App_Plugins/BlockList/Thumbnails/Quote.png.

@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Serialization

@inherits UmbracoViewPage

@inject PropertyEditorCollection PropertyEditors
@inject IDataTypeService DataTypeService
@inject IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer
@inject IContentTypeService ContentTypeService

@{

    // Get ID of the folder in which the new data type will be created
    int parentId = 1122;

    // Get a reference to the block list property editor
    IDataEditor editor = PropertyEditors
        .Single(x => x.Alias == Constants.PropertyEditors.Aliases.BlockList);

    // Declare a list for the block configurations
    List<BlockListConfiguration.BlockConfiguration> blocks = new();

    // Get reference to the content types (element types) that we wish to allow for the block list
    IContentType? quoteBlockContentType = ContentTypeService.Get("quoteBlock");
    IContentType? rteBlockContentType = ContentTypeService.Get("rteBlock");
    IContentType? vimeoBlockContentType = ContentTypeService.Get("vimeoBlock");
    if (quoteBlockContentType is null) throw new Exception("Oh noes!");
    if (rteBlockContentType is null) throw new Exception("Oh noes!");
    if (vimeoBlockContentType is null) throw new Exception("Oh noes!");

    // Append the "Quote" block configuration
    blocks.Add(new BlockListConfiguration.BlockConfiguration
    {
        ContentElementTypeKey = quoteBlockContentType.Key
    });

    // Append the "Text" block configuration
    blocks.Add(new BlockListConfiguration.BlockConfiguration
    {
        ContentElementTypeKey = rteBlockContentType.Key,
        Label = "Text"
    });

    // Append the "Vimeo" block configuration
    blocks.Add(new BlockListConfiguration.BlockConfiguration
    {
        ContentElementTypeKey = vimeoBlockContentType.Key
    });

    // Initialize the configuration object
    BlockListConfiguration config = new BlockListConfiguration
    {
        Blocks = blocks.ToArray(),
        ValidationLimit = new BlockListConfiguration.NumberRange { Min = null, Max = null },
        UseSingleBlockMode = false,
        UseLiveEditing = false,
        UseInlineEditingAsDefault = false,
        MaxPropertyWidth = "100%"
    };

    // Get the default database type
    ValueStorageType databaseType = ValueTypes
        .ToStorageType(editor.GetValueEditor(config).ValueType);

    // Initialize a new data type
    IDataType dataType = new DataType(editor, ConfigurationEditorJsonSerializer, parentId)
    {
        Name = "My block list",
        DatabaseType = databaseType,
        Configuration = config
    };

    // Create/save the data type to the database
    DataTypeService.Save(dataType);

    // Print out the ID
    <pre>@dataType.Id</pre>

}

 

Media

Adding media with physical files are a bit complex. To add a file to a media, you have to use the special IMedia.SetValue extension method. The extension method that you'll need is located in the Umbraco.Exensions namespace.

Umbraco has a number of SetValue methods, but the one you'll need where the first five parameters match the following types:

  • MediaFileManager
  • MediaUrlGeneratorCollection
  • IShortStringHelper
  • IContentTypeBaseServiceProvider

Creating a new image from a file on disk

A new media may be created from a file on disk using the following steps:

  1. map/declare the path to the file
  2. declare the new filename
  3. open a new stream to the file on disk
  4. create a new media in memory
  5. use the special .SetValue() extension method to set the media file
  6. save the media

Using these steps, Umbraco will automatically populate the umbracoWidthumbracoHeightumbracoBytess and umbracoExtension properties with the correct values.

If you for instance are using Azure blob storage, and have configured this correctly for your website, Umbraco will also automatically upload the media file to the blob container rather than saving it to disk.

@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.Strings
@using Umbraco.Cms.Core.IO
@using System.IO
@using Umbraco.Cms.Core
@using Microsoft.AspNetCore.Hosting
@using File = System.IO.File

@inherits UmbracoViewPage

@inject IWebHostEnvironment WebHostEnvironment
@inject IMediaService MediaService
@inject MediaFileManager MediaFileManager
@inject MediaUrlGeneratorCollection MediaUrlGeneratorCollection
@inject IShortStringHelper ShortStringHelper
@inject IContentTypeBaseServiceProvider ContentTypeBaseServiceProvider

@{

    // Map the path to the image file on disk
    string imagePath = WebHostEnvironment.MapPathWebRoot("~/unicorn.jpg");

    // Declare the file name of the image
    string imageName = "unicorn.jpg";

    // Open a stream for the file on disk
    await using Stream stream = File.OpenRead(imagePath);

    // Create a new media in memory
    IMedia media = MediaService.CreateMedia("Unicorn", -1, Constants.Conventions.MediaTypes.Image);

    // Set the "umbracoFile" property using the stream
    media.SetValue(MediaFileManager, MediaUrlGeneratorCollection, ShortStringHelper, ContentTypeBaseServiceProvider, Constants.Conventions.Media.File, imageName, stream);

    // Save and persists the media to the database
    MediaService.Save(media);

    <pre>@media.Id</pre>
    <pre>@media.Key</pre>

}

Creating a new image from an URL

A new media may be created from a file on disk using the following steps:

  1. map/declare the path to the file
  2. declare the new filename
  3. get a new HttpClient from IHttpClientFactory
  4. open a new stream to the remote file
  5. create a new media in memory
  6. use the special .SetValue() extension method to set the media file
  7. save the media
@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.Strings
@using Umbraco.Cms.Core.IO
@using System.Net.Http
@using Umbraco.Cms.Core
@using System.IO

@inherits UmbracoViewPage

@inject IMediaService MediaService
@inject IHttpClientFactory HttpClientFactory
@inject MediaFileManager MediaFileManager
@inject MediaUrlGeneratorCollection MediaUrlGeneratorCollection
@inject IShortStringHelper ShortStringHelper
@inject IContentTypeBaseServiceProvider ContentTypeBaseServiceProvider

@{

    // Declare the URL to the image
    string imageUrl = "https://umbraco.com/media/br4ddn0l/umbraco-12-square_dark_500x500px-80.jpg";

    // Declare the file name of the image
    string imageName = "umbraco12.jpg";

    // Create a new HTTP client from the factory
    using HttpClient client = HttpClientFactory.CreateClient();

    // Download the remote image
    await using Stream stream = await client.GetStreamAsync(imageUrl);

    // Create a new media in memory
    IMedia media = MediaService.CreateMedia("Umbraco 12", -1, Constants.Conventions.MediaTypes.Image);

    // Set the "umbracoFile" property using the stream
    media.SetValue(MediaFileManager, MediaUrlGeneratorCollection, ShortStringHelper, ContentTypeBaseServiceProvider, Constants.Conventions.Media.File, imageName, stream);

    // Save and persists the media to the database
    MediaService.Save(media);

    <pre>@media.Id</pre>
    <pre>@media.Key</pre>

}

Accessing a media file for an existing media

Depending on how a Umbraco installation is configured, media files may either be stored locally on disk or somewhere else (eg. Azure Blob Storage). This means that in order to open a file, we can't rely on File.OpenRead.

Instead we can use Umbraco's MediaFileManager class, which exposes an IFileSystem via the FileSystem property. The IFileSystem instance then has a OpenFile method, that returns a Stream that we can use.

Notice how I'm using the .TryGetMediaPath() extension method for getting the relative path of the media. For regular files, the media's umbracoFile will simply be the relative path to the media file, but for images, the property value will instead be a JSON object including both the relative path as well as various cropping information for the image. Instead of reinventing the wheel, we can rely on Umbraco's extension method to parse and return the relative path for us.

@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.IO
@using System.IO
@inject IMediaService MediaService
@inject MediaUrlGeneratorCollection MediaUrlGeneratorCollection
@inject MediaFileManager MediaFileManager

@{

    // Get a reference to the media
    IMedia? media = MediaService.GetById(1313);
    if (media is null)
    {
        throw new Exception("Oh noes!");
    }

    // Try to get the relative path to the media file
    if (!media.TryGetMediaPath("umbracoFile", MediaUrlGeneratorCollection, out string? mediaFilePath))
    {
        throw new Exception("Oh noes!");
    }

    <pre>Relative path: @mediaFilePath</pre>

    // Open a new stream to the file
    await using Stream stream = MediaFileManager.FileSystem.OpenFile(mediaFilePath);

    // Do something with the stream

}

Anders Bjerner

Anders Bjerner is an Umbraco MVP and System Developer at Limbo (formerly Skybrud.dk), with offices in Vejle and Copenhagen, Denmark. He has a background in Computer Science, and has been working with Umbraco since 2011. His work at Limbo typically consists of implementing Umbraco solutions for various government and private clients as well as developing custom packages (where a number of them can be found on the Umbraco Marketplace and NuGet). When not working and playing around with Umbraco, he can be found on his bike exploring the hills around his hometown (some of the steepest/highest in an otherwise flat Denmark).

comments powered by Disqus