Convert File system based Media to Database storage in Sitecore

Introduction:

We had a large enterprise sitecore application where there were thousands of media items where the actual media was stored in filesystem and there were another set of thousands of media items which were stored in database. This combination made it difficult to maintain and it also did not make sense to have two different ways of storing media. Hence decided to convert the file system based media to database media storage.

Challenges

For unversioned template, we can have a custom code where we download the media, delete all versions and upload the same media to the same item and version. Since we have set the config to upload media as a database based so it will be uploaded as database. So this is a straightforward conversion.

For versioned template, we had to convert the media in one language version and upload the converted media in the same language version. But while uploading the media to sitecore it will check for a property which indicates whether the media item is a file based media or not. Since the media item is still a file based media item because the media present in other language version is still file based media, the converted media will still be uploaded as a file based media even though we have set the config to upload media as a database based.

Solution:

The sitecore will treat the media item as a file based media item or a databased item based on the Property “FileBased” . If there is any version in the media item which is file based then the Property “FileBased” will be set to true. Hence if you upload any media in any language version , it will be uploaded as a file based Media even though we have set the config to upload the media as a database storage. So we came up with below work around to fix this issue.

  1. Duplicate the media item.
  2. Delete all the versions of the original item and then make the original item as database storage item.
  3. Copy/attach the media from the duplicate item to the original item language by language

Complete custom code can be found below:

public bool ConvertMediaToDatabase(string itemPath)
{
using (new EnforceVersionPresenceDisabler())
{
Sitecore.Data.Items.Item item = database.GetItem(itemPath);
Sitecore.Data.Items.MediaItem mediaItem = item;
Sitecore.Data.Items.Item duplicateItem = item.CopyTo(item.Parent, item.Name + "copy");
var altText = mediaItem.Alt;
var mediaItemFullPath = mediaItem.InnerItem.Paths.Path;
var mediaCreatorOptions = new MediaCreatorOptions
{
FileBased = false,
Destination = mediaItemFullPath,
OverwriteExisting = true,
Versioned = true,
AlternateText = altText
};
var filename = mediaItem.Name + "." + mediaItem.Extension;
using (new SecurityDisabler())
{
if (AttachStreamToMediaItem(duplicateItem, mediaItemFullPath, mediaCreatorOptions))
{
duplicateItem.Delete();
return true;
}
else
return false;
}
}
}
public bool AttachStreamToMediaItem(Item duplicateItem, string itemPath, MediaCreatorOptions options)
{
Assert.ArgumentNotNull(options, "options");
Assert.ArgumentNotNull(itemPath, "itemPath");
FileStream filestream;
try
{
using (new EnforceVersionPresenceDisabler())
{
Item item = CreateItem(itemPath, duplicateItem.TemplateID, options);
Language[] itemLanguages = GetItemMediaLanguages(options, duplicateItem);
if (itemLanguages != null && itemLanguages.Any())
{
foreach (Language language in itemLanguages)
{
Sitecore.Data.Items.MediaItem mediaItem = database.GetItem(duplicateItem.ID, language);
Sitecore.Data.Items.MediaItem langitem = database.GetItem(item.ID, language);
Media media = MediaManager.GetMedia(langitem);
if (mediaItem != null && !string.IsNullOrEmpty(mediaItem.FilePath) && langitem != null)
{
var path = ModifyFilePath(mediaItem.FilePath, langitem.ID.ToString());
var filePath = Sitecore.IO.FileUtil.MapPath(path);
string extension = FileUtil.GetExtension(filePath);
using (new EditContext(langitem, SecurityCheck.Disable))
{
langitem.Extension = Sitecore.StringUtil.GetString(mediaItem.Extension, extension);
langitem.Alt = StringUtil.GetString(mediaItem.Alt, options.AlternateText);
langitem.InnerItem["Width"] = mediaItem.InnerItem["Width"] != null ? mediaItem.InnerItem["Width"] : "";
langitem.InnerItem["Height"] = mediaItem.InnerItem["Height"] != null ? mediaItem.InnerItem["Height"] : "";
langitem.InnerItem.Statistics.UpdateRevision();
}
using (filestream = new FileStream(filePath, FileMode.Open))
{
media.SetStream(filestream, extension);
}
}
}
return true;
}
}
}
catch (DirectoryNotFoundException ex)
{
Log.Error("Directory Not Found", ex.Message);
}
catch (FileNotFoundException ex)
{
Log.Error("File Not Found", ex.Message);
}
catch (Exception ex)
{
Log.Error("Error while attaching stream to media", ex.Message);
}
return false;
}
protected Item CreateItem(string itemPath, Sitecore.Data.ID templateId, MediaCreatorOptions options)
{
Assert.ArgumentNotNullOrEmpty(itemPath, "itemPath");
Assert.ArgumentNotNull(options, "options");
Item item2;
using (new EnforceVersionPresenceDisabler())
{
using (new SecurityDisabler())
{
Item item = (options.OverwriteExisting ? database.GetItem(itemPath) : null);
string itemName = GetItemName(itemPath);
item2 = item;
item2.Versions.RemoveAll(true);
item2 = item2.Database.GetItem(item2.ID, item2.Language, Sitecore.Data.Version.Latest);
Assert.IsNotNull(item2, "item");
item2.Editing.BeginEdit();
foreach (Field field in item2.Fields)
{
field.Reset();
}
item2.Editing.EndEdit();
item2.Editing.BeginEdit();
item2.Name = itemName;
item2.TemplateID = templateId;
item2.Editing.EndEdit();
}
}
Assert.IsNotNull(item2, typeof(Item), "Could not create media item: '{0}'.", itemPath);
item2.Reload();
return item2;
}
private string GetItemName(string itemPath)
{
using (new EnforceVersionPresenceDisabler())
{
Assert.ArgumentNotNull(itemPath, "itemPath");
string lastPart = Sitecore.StringUtil.GetLastPart(itemPath, '/', string.Empty);
if (string.IsNullOrEmpty(lastPart))
{
if (!Settings.Media.IncludeExtensionsInItemNames)
{
return "unnamed";
}
throw new InvalidOperationException("Invalid item path for media item: " + itemPath);
}
return lastPart;
}
}
protected virtual Language[] GetItemMediaLanguages(MediaCreatorOptions options, Item item)
{
Assert.ArgumentNotNull(options, "options");
Assert.ArgumentNotNull(item, "item");
Assert.Required(item.Database, "item.Database");
using (new EnforceVersionPresenceDisabler())
{
if (!options.Versioned)
{
return item.Database.Languages;
}
else
{
var itemLanguages = ItemManager.GetContentLanguages(item)
.Select(lang => new { Language = lang, HasLanguage = ItemManager.GetVersions(item, lang).Count > 0 })
.Where(langInfo => langInfo.HasLanguage)
.Select(langInfo => langInfo.Language).ToArray();
return itemLanguages;
}
}
}
private string ModifyFilePath(string filePath, string itemId)
{
string newid = filePath.Split('{', '}')[1];
return filePath.Replace(newid, itemId.Split('{', '}')[1]);
}

Using this custom code I was able to convert thousands of media Item from file system based to database storage. It was a smooth process without any issues.

Please let me know for any Queries\Feedback.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a free website or blog at WordPress.com.

Up ↑

%d bloggers like this: