Media Library Inline Editor

Selecting images from the Media Library in Kentico 12 MVC

Why would I need it?

It's pretty simple - every website contains images nowadays. And any modern CMS must give the editors the ability to choose images to display quite easily. As you may have noticed, Kentico 12 MVC Dancing Goat sample website contains inline editor allowing to select the image from the file system. Then, image is being uploaded into the CMS and stored as a page attachment. Pretty simple and straightforward. But what if you want to store all the media files in just one place keeping the convenient structure and reuse the same items without uploading them multiple times? Here is where Media Libraries come to the resque. But there is no inline editor for it you may say! Luckily, it's pretty simple to write your own.

Quick demo

Final result will look something like this:

Inline editor demo

TL;DR

For "just using it as it is" the full code can be downloaded from here.

All you need to do after:

  • Extract the code into the appropriate folders
  • Register HashServiceMediaService and MediaRepository with your favourite IoC
    For example, with LightInject it would be:
public class CompositionRoot : ICompositionRoot
{
    public void Compose(IServiceRegistry serviceRegistry)
    {
        serviceRegistry.RegisterScoped<IMediaRepository, MediaRepository>();
        serviceRegistry.RegisterScoped<IMediaService, MediaService>();
        serviceRegistry.RegisterScoped<IHashService, HashService>();
    }
}
  • In the MediaService amend:
    • _imageExtensions constant to match your media file extensions
    • _libraryName to match your Media Library name (in this implementation there is no ability to change the Media Library on the fly, it's hardcoded)
  • In the MediaRepository amend _libraryName constant to match your Media Library name
  • Now you can use this inline editor in your widgets like this:
@using diger74.Models.InlineEditors.ImageEditor
@model diger74.Models.Media.ImageModel

<!-- Render button in the admin area -->
@if (Context.Kentico().PageBuilder().EditMode)
{
    Html.RenderPartial("InlineEditors/_MediaEditor", new MediaEditorViewModel
    {
        PropertyName = "Image",
        Title = "Image",
        ImageUrl = Model?.Url,
        ImageFolderPath = Model?.FolderPath,
        ImageId = Model?.Id,
        FileName = Model?.FileName,
        Order = 0
    });
}

<!-- Render image with alt -->
<img src="@Model?.Url" alt="@Model?.Title">
  • Note the Order variable: if your widget contains more than just one image, you can set the order and image selection buttons will stack automatically

Key things under the hood

Basically, for this Media Library Inline Editor consists of two parts:

  • Backend service:
    • Returns the folder tree of the Media Library
    • Returns the list of files in the selected folder
  • Frontend:
    • Displays the media picker button
    • Opens the media selection dialog in the overlay

In the code of MediaRepository you may notice quite important thing: it relies on Kentico default MediaFileInfoProvider to list all the media files and build a folder tree to display.

    public class MediaRepository : IMediaRepository
    {
        private readonly string _libraryName = "Default";
        private readonly string _baseCacheKey = "default|mediafile";

        public IEnumerable<MediaFileInfo> GetAllMediaFilesByLibraryName()
        {
            var cacheKey = $"{_baseCacheKey}|{_libraryName}|all";

            var mediaFiles = new List<MediaFileInfo>();

            using (var cs = new CachedSection<List<MediaFileInfo>>(ref mediaFiles, CacheHelper.CacheMinutes(SiteContext.CurrentSiteName), true, cacheKey))
            {
                if (cs.LoadData)
                {
                    var library =
                        MediaLibraryInfoProvider.GetMediaLibraryInfo(_libraryName, SiteContext.CurrentSiteName);

                    mediaFiles = MediaFileInfoProvider.GetMediaFiles()
                        .WhereEquals("FileLibraryID", library?.LibraryID ?? 0)
                        .ToList();

                    var cacheDependencies = new List<string>
                    {
                        $"{MediaFileInfo.OBJECT_TYPE}|all"
                    };

                    cs.Data = mediaFiles;
                    cs.CacheDependency = CacheHelper.GetCacheDependency(cacheDependencies);
                }
            }

            return mediaFiles;
        }
    }
}

It may look easier to use System.IO.Directory.GetFiles(..) instead. But you will face the big problem with this approach if you would store Media Library on Azure Storage according to the best practices from Kentico. It just won't work. But getting the paths from database via Kentico MediaLibraryInfoProvider will!

So just give this inline editor a try and happy coding!