Kentico Poster

How not to be shy on stage: Fixing a Kentico 'Gotcha'

Using the Kentico API to insert media files into a Media Library, and a solution to when those items do not appear in the Kentico Staging queue.

Emmanuel Tissera

03 September 2015

5 minute read

As a WCMS, Kentico is tasked with managing content and media images for a website. The usual practice involves a Content Editor uploading content and images via the Kentico back-office. But what happens when you want to automate that process and remove that human element?

Recently we worked on a project which used the Kentico API to upload images into the Kentico Media Library without human intervention. Then those items were synced to the next environment. The following 'how to' guide provides a step by step solution on how to do this. The guide also explains how to circumvent the issue when these automated uploads to do not appear on the Kentico Staging queue.

Our Requirement - Kentico API Calls

Our requirement was to create a media file from a Windows Service. The Windows Service was also tasked with other image manipulation tasks which is outside the scope of this discussion. Once the image was added to the Media Library, we wanted Kentico Staging to take care of synchronisation to the next environment.

What we did - Samples to the rescue

We used the examples given in the Kentico documentation as a starting point. You can see the relevant code in ~/CMSAPIExamples/Code/Tools/MediaLibrary/Default.aspx in your own Kentico installation.

More info on using the API is available at https://docs.kentico.com/display/K82/Using+Kentico+API+and+Controls+externally.

Our code is given below as a quick reference. The following is created as a Windows Console application to keep the sample as lean as possible.

Referenced Assemblies

Contrary to the Kentico documentation, you don't need to reference all the DLLs in the LIB directory. But it does pull many of those through to your project output folder. The assemblies which need to be referred for this particular task are listed below.

  • CMS.Base
  • CMS.DataEngine
  • CMS.DataProviderSQL
  • CMS.FileSystemStorage
  • CMS.IO
  • CMS.MediaLibrary
  • CMS.Membership

Also note that since CMS.DataProviderSQL and CMS.FileSystemStorage are loaded dynamically at runtime, they do not get copied to the output of a referencing project (in case you are writing a library). You can write this piece of code to get over manually copying the files each time.


private static void IncludeDependentAssemblies()


{


CMS.FileSystemStorage.Directory directory = new CMS.FileSystemStorage.Directory();


CMS.DataProviderSQL.TableManager tableManager = new CMS.DataProviderSQL.TableManager();


}

view rawIncludeDependentAssemblies.cs hosted with ❤ by GitHub

Essential Configuration


<?xml version="1.0" encoding="utf-8" ?>


<configuration>


<connectionStrings>


<clear />


<add name="CMSConnectionString" connectionString="..." />


</connectionStrings>


</configuration>

view rawapp.xml hosted with ❤ by GitHub

Code Sample


using CMS.Base;


using CMS.IO;


using CMS.MediaLibrary;


using CMS.Membership;


using System;




namespace KenticoMediaLibraryConsole


{


internal class Program


{


// Note that this version does not push items to the Kentico Staging Queue


// See https://gist.github.com/emmanuel-tissera-gs/19ec7fe4b9135398c45f for fix


private static void Main(string[] args)


{


(new MediaFileSample()).AddMediaLibraryItem();


}


}




public class MediaFileSample


{


private UserInfo User


{


get { return CMS.Membership.UserInfoProvider.GetUserInfo("Administrator"); }


}




public void AddMediaLibraryItem()


{


CMS.Base.SystemContext.WebApplicationPhysicalPath = @"C:\inetpub\wwwroot\Site\CMS";


CMS.DataEngine.CMSApplication.Init();




var libraryName = DateTime.Now.ToString("yyyyMMdd-HHmm");


var library = CreateMediaLibrary(libraryName);




var mediaFile = GetInitializedMediaFile(library);




if (mediaFile != null)


{


MediaFileInfoProvider.SetMediaFileInfo(mediaFile);


CMSWorkerQueue.RunCurrentQueuedWorkers();


}


}




private MediaLibraryInfo CreateMediaLibrary(string libraryName)


{


using (new CMSActionContext(User))


{


var library = new MediaLibraryInfo();




// Set the properties


library.LibraryDisplayName = libraryName + " Display";


library.LibraryName = libraryName;


library.LibraryDescription = libraryName + " Description";


library.LibraryFolder = libraryName;


library.LibrarySiteID = 1;


library.LibraryLastModified = DateTime.Now;




// Create the media library


MediaLibraryInfoProvider.SetMediaLibraryInfo(library);




return library;


}


}




private MediaFileInfo GetInitializedMediaFile(MediaLibraryInfo library)


{


MediaFileInfo mediaFile = null;




if (library != null)


{


var filePath = @"C:\Powered_by_kentico2.gif";




// Create file info


FileInfo file = FileInfo.New(filePath);




using (new CMSActionContext(User))


{


mediaFile = new MediaFileInfo(filePath, library.LibraryID)


{


FileName = file.Name,


FileTitle = "File Title",


FileDescription = "A Description for the file",


FilePath = "MyNewFile.gif",


FileExtension = file.Extension,


FileMimeType = "image/gif",


FileSiteID = 1,


FileLibraryID = library.LibraryID,


FileSize = file.Length,


FileModifiedByUserID = User.UserID


};


}


}




return mediaFile;


}


}


}

view rawprogram.cs hosted with ❤ by GitHub

You would need to have an image file such as "C:\Powered_by_kentico2.gif" in place and set the CMS.Base.SystemContext.WebApplicationPhysicalPath to your Kentico installation for the above sample to run.

What happened

As expected the media library was created along with the media file. The physical file was copied to the corresponding folder within the CMS folder structure as well.

But the items which were created using the API did not show up on the Kentico Staging queue.

How it was fixed

Having items on the Kentico Staging queue was a key requirement for our solution. So we engaged the Kentico Support team via e-mail to sort this issue out. After a few false starts, Kentico Support was able to provide us with a solution. It was just one line of code - but it did take some time and a few e-mails to figure out and fix. The line of code is shown in context below.

CMSWorkerQueue.RunCurrentQueuedWorkers();


public void AddMediaLibraryItem()


{


CMS.Base.SystemContext.WebApplicationPhysicalPath = @"D:\inetpub\wwwroot\Site\CMS";


CMS.DataEngine.CMSApplication.Init();


var libraryName = DateTime.Now.ToString("yyyyMMdd-HHmm");


var library = CreateMediaLibrary(libraryName);


var mediaFile = GetInitializedMediaFile(library);


if (mediaFile != null)


{


MediaFileInfoProvider.SetMediaFileInfo(mediaFile);


CMSWorkerQueue.RunCurrentQueuedWorkers();


}


}

view rawStagingSynchronization.cs hosted with ❤ by GitHub

Upon inspection of the original code it was found that logging of Staging tasks and processing runs in a different thread. In order for that thread to complete its work, CMSWorkerQueue.RunCurrentQueuedWorkers() should be called.

Conclusion

Working within a website, the Staging synchronisation would not be an issue. But when working with the Kentico API out of the web context, knowing about this issue and the solution for it could be a life saver.

Enjoy!

Want to know more?

We have a whole team of experts who would love to talk to you.

Get in touch

Keep Reading

Want more? Here are some other blog posts you might be interested in.