Allowing Episerver editors to create media content

By default, and probably as you'd expect, editors can't 'create' media in Episerver (aside from uploading it). However, it's not that outlandish a proposition that they'd want to be able to reference external media like videos or images hosted elsewhere.

Whilst you could of course just create a block type, it would be nice if this content was available through the Media tab in the assets pane, which is where it would logically be expected.

I recently did a very quick proof of concept to see how this could be achieved, and the purpose of this blog post is to show you how you can achieve something like this:

Creating new media in Episerver CMS

It also turns out to be relatively easy to do with just three steps, all of which are conveniently documented below:

The content type

First, we need to create our content type, this should match your exact requirements...but I'd expect it to look something like this:

[ContentType(
    DisplayName = "External Video",
    GUID = "677C310B-E30E-4D25-B8C4-2615C1A01090",
    Order = 30)]
public class ExternalVideoMediaType : ContentBase, IContentVideo, ILocalizable
{
    [Required]
    [CultureSpecific]
    [Display(Name = "Url", Order = 10)]
    public virtual string Url { get; set; }

    public IEnumerable<CultureInfo> ExistingLanguages { get; set; }
    public CultureInfo MasterLanguage { get; set; }
    public CultureInfo Language { get; set; }

    public Blob BinaryData { get; set; }
    public Uri BinaryDataContainer { get; set; }
    public Blob Thumbnail { get; set; }
    public string MimeType { get; set; }
}

In this example we implement IContentVideo (which is why we have BinaryData, BinaryDataContainer etc.) which will allow editors to interact with it as if it was a standard video.

Allowing editors to create our new content type

Now we need to create a repository descriptor (see 'Content repository descriptors' in the Episerver developer guide) that allows the editor to create our ExternalVideoMediaType. We can just inherit the existing MediaRepositoryDescriptor and override the CreatableTypes (which is normally an empty array):

[ServiceConfiguration(typeof(IContentRepositoryDescriptor))]
public class CustomMediaRepositoryDescriptor : MediaRepositoryDescriptor
{
    public override IEnumerable<Type> CreatableTypes => new[] { typeof(ExternalVideoMediaType) };
}

We can now simply unregister the default MediaRepositoryDescriptor as our own is already registered (via the ServiceConfiguration attribute):

[InitializableModule]
[ModuleDependency(typeof(ServiceContainerInitialization))]
public class RemoveMediaRepositoryDescriptorInitialization : IConfigurableModule
{
    public void Initialize(InitializationEngine context) { }
    public void Uninitialize(InitializationEngine context) { }
    public void ConfigureContainer(ServiceConfigurationContext context)
    {
        var contentRepositoryDescriptorConfig = context.StructureMap().Model.PluginTypes
            .SingleOrDefault(x => x.PluginType == typeof(IContentRepositoryDescriptor));

        var instance = contentRepositoryDescriptorConfig?.Instances.SingleOrDefault(x =>
                x.ReturnedType == typeof(MediaRepositoryDescriptor));

        if (instance == null)
        {
            return;
        }

        contentRepositoryDescriptorConfig.EjectAndRemove(instance);
    }
}

Another option here would be to also override the repository key in our CustomMediaRepositoryDescriptor, then remove the default media view from the assets pane and finally register our own. However, the above seemed to work fine as part of my PoC!

Disabling some views for our media content type

Finally, we can go ahead and disable some of the views for the newly added ExternalVideoMediaType (leaving only the All properties view):

[UIDescriptorRegistration]
public class ExternalVideoUIDescriptor : UIDescriptor<ExternalVideoMediaType>, IEditorDropBehavior
{
    public ExternalVideoUIDescriptor() : base("epi-iconObjectVideo")
    {
        ContainerTypes = new[] { typeof(ContentFolder) };
        DefaultView = CmsViewNames.AllPropertiesView;
        DisabledViews = new[]
        {
            CmsViewNames.PreviewView, CmsViewNames.OnPageEditView, CmsViewNames.AllPropertiesCompareView,
            CmsViewNames.ContentListingView, CmsViewNames.SideBySideCompareView
        };
        EditorDropBehaviour = EditorDropBehavior.CreateContentBlock;
    }

    public EditorDropBehavior EditorDropBehaviour { get; set; }
}

With that, we're done! Or rather, you're on your own from this point!

Comments

There are zero comments 😢