Often in developing Kentico sites we will utilize the media library for storage and management of files for a project. This functionality provides a great way to organize and store files and is a great addition to any application. When migrating an existing site to Kentico we encounter an issue of having several media library files to import. This blog details how I created a Kentico module to recursively import files into the site.
1. Create the Base Module Code
For the project, there is nothing out of the ordinary for the base module. Kentico provides great documentation to walk you through this process in the developers guide
here.
Loading the Media Libraries
//Get the media libraries
DataSet dsLibraries = MediaLibraryInfoProvider .GetMediaLibraries("" , null );
if (!DataHelper .DataSourceIsEmpty(dsLibraries))
{
//Set the drop down data source to the libraries dataset
ddlMediaLibraries.DataValueField = "LibraryID" ;
ddlMediaLibraries.DataTextField = "LibraryName" ;
ddlMediaLibraries.DataSource = dsLibraries;
ddlMediaLibraries.DataBind();
}
2. Add Selectors for the Libraries / Folders
For this project, I decided to allow the utility to function on individual media libraries and/or their nested folders. A user selects a media library to import from, then chooses the desired “root” folder to import. The user can also select whether to import the single folder, or subfolders beneath the selected item. There is also an option to allow selecting the “root” media library folder, which in conjunction with the “Include Subfolders” option would allow an entire media library to be imported at once.
Loading the Media Library Folders
//Get the selected library id
int iLibraryID = Convert .ToInt32(ddlMediaLibraries.SelectedValue.ToString());
if (iLibraryID > 0)
{
MediaLibraryInfo med = MediaLibraryInfoProvider .GetMediaLibraryInfo(iLibraryID);
if (med != null )
{
//Build up the file path to media library folder
string strFilePath = Server.MapPath("~" );
strFilePath = strFilePath + "\\\\" + CMSContext .CurrentSiteName + "\\\\media\\\\" + med.LibraryFolder;
DirectoryInfo [] dir = new DirectoryInfo (strFilePath).GetDirectories();
//Clear the current folders
ddlMediaLibraryFolders.Items.Clear();
//Add the first item for the root
ddlMediaLibraryFolders.Items.Add(new ListItem ("--Media Library Root--" , "" ));
//Load the folders into the folder drop down
foreach (DirectoryInfo dirSub in dir)
{
ddlMediaLibraryFolders.Items.Add(new ListItem (dirSub.Name, dirSub.Name));
}
}
}
3. Add the Magic
The real functionality of the module comes in how it recursively reads through and imports files. This is achieved by leveraging Kentico APIs and custom functionality. I started with Kentico’s existing code as a base and modified it for my needs.
Tip
The media import process needs files without spaces in order to complete the process properly. The module will rename files by replacing spaces with dashes as it works through the files.
Importing Files
strFullPath = fileRoot.FullName;
//Make sure the file name does not contain spaces
if (fileRoot.FullName.IndexOf(" " ) > -1)
{
//Rename the file to prevent an error due to spaces in file names
CMS.IO.File .Move(fileRoot.FullName.ToString(), fileRoot.FullName.ToString().Replace(" " , "-" ));
strFullPath = fileRoot.FullName.Replace(" " , "-" );
}
try
{
//Create the new Media File object
//This call will generate an exception if the file already exists
MediaFileInfo fileInfo = new MediaFileInfo (strFullPath, iLibraryID, strRoot);
fileInfo.FileTitle = fileRoot.Name;
fileInfo.FileDescription = fileRoot.Name;
// Save media file info
MediaFileInfoProvider .ImportMediaFileInfo(fileInfo);
//Add file to list of imported
sbImportedFiles.Append("<br />" + fileInfo.FilePath);
fileInfo = null ;
iImported += 1;
}
Note
The Bit-Wizards Media Library Importer currently is configured to read 2 levels into a media library for importing. This functionality can easily be expanded by adding additional recursion code. This is noted in the source code.
4. Add Detailed Reporting
In developing the module, I found it beneficial to know what files were actually being published. I added a small option to record the file path / name of each imported file and the user can choose where or not view this information.
Detailed Reporting
//Determine the result output detail level
if (cbDetailedResults.Checked)
{
SetMessage("Total Imported: " + iImported.ToString() + "<br />" + sbImportedFiles.ToString() + "<br />Total Already Imported: " + iAlreadyImported.ToString() + "<br /><br />Total Skipped: " + iSkipped.ToString() + "<br />" + sbSkippedFiles.ToString(), false );
}
else
{
SetMessage("Total Imported: " + iImported.ToString() + "<br /><br />Total Already Imported: " + iAlreadyImported.ToString() + "<br /><br />Total Skipped: " + iSkipped.ToString(), false );
}
5. Add Error Handling
Every good application has ample error handling in the event of a problem ("Ain't nobody got time for that!"). I added standard Kentico Exception handling and am writing all errors to the Event Log for easy storage and review. If your site is configured to receive error notifications, the module will publish these directly to your account when they occur.
Tip
I use Kentico Exception Handling in all of my code due to its ease of implementation and configuration. With the one line of code below you get great exception handling and logging.
try
{
if (strMsg != "" )
{
if (blnError)
{
lblMessage.Text = "<h4 style=\\"color: red;\\">" + strMsg + "</h4>" ;
}
else
{
lblMessage.Text = "<h4>" + strMsg + "</h4>" ;
}
}
else
{
lblMessage.Text = "" ;
}
}
catch (Exception ex)
{
EventLogProvider .LogException("Bit-Wizards Media Library Importer" , "Exception" , ex);
SetMessage("There was an error in the module. Please check the event log for details." , true );
}