Thursday, May 27, 2010

Keeping Media Metadata In Sync

When media files are uploaded to Sitecore, a Sitecore item is created. This item represents the media file in Sitecore. When you want to display information about the media file, you are displaying information about the item. When the file is updated, Sitecore ensures that the fields on the item stay in sync with the file.

Well, Sitecore does this for fields it is aware of. This is handled by the Sitecore.Resources.Media.Media class (and the classes that inherit from it). Thanks to the ImageMedia class, when you upload an image file, the height and width are read. Sitecore does not include a class to handle Microsoft Word documents, so metadata from those files is NOT read.

Creating a class to read metadata from Word documents, or any other file, is not hard to do. Sitecore is already set up to allow it. You just need to write the code that can read the metadata from the media file. The Sitecore Experience blog has a post that explains how to do this.

But what if you want a change to go the other direction? What if you want to update the document title in a Word document using Sitecore? This is also possible, but requires a little more work. In this post I'm going to explain how to do this for a docx file.

Triggering code when the Sitecore item is saved
When the Sitecore item is changed, code needs to run that updates the corresponding media file. This is accomplished by hooking into the "item:saved" event in web.config (or other config file).

<events>
<event name="item:saved">
<handler type="Sitecore.Marketing.MediaLibrary.MediaItemSavedHandler, Sitecore.Marketing.MediaLibrary" method="OnItemSaved"/>
</event>
</events>


And the MediaItemSavedHandler class must be defined. The rest of the code in this post goes inside this class.

public class MediaItemSavedHandler
{
protected void OnItemSaved(object sender, EventArgs args)
{
}
}



Determining if the item represents a media file
Since this event handler applies to all items, it is important to determine if the item that was saved represents a media file. This can be accomplished by checking the item's template ID.

Item item = Event.ExtractParameter(args, 0) as Item;
bool isDocx = item.TemplateID.ToString().Equals("{7BB0411F-50CD-4C21-AD8F-1FCDE7C3AFFE}");
if (!isDocx)
{
return;
}


Determining if the title has actually changed
Just because the item saved event is triggered doesn't mean it was triggered by a change to the title. The EventArgs parameter will indicate if the title has changed:

ItemChanges changes = Event.ExtractParameter(args, 1) as ItemChanges;
Field titleField = item.Fields["Title"];
bool hasTitleChanged = (changes.HasFieldsChanged && titleField != null && changes.IsFieldModified(titleField));
if (!hasTitleChanged)
{
return;
}
MediaItem media = new MediaItem(item);



Updating the media file
Next you need to update the media file in Sitecore. Access to Sitecore media files is available through the WebDAV interface, but communicating with the WebDAV server is a topic for a separate post. I'm going to take the easy way out here: I'm going to read the current file to a temp file, update the temp file, then replace the file in Sitecore.

Additionally, I'm not going to include all of the code needed update the docx file. I'll show you how to read a file from the media library and how to write a file to the media library.

If you're familiar with how .NET handled I/O, there's not much to accessing the media file. Here is an example of how to read and write Sitecore media files.

protected string CreateTempFile(MediaItem media)
{
string fileName = Path.GetTempFileName();
using (FileStream file = new FileStream(fileName, FileMode.Open))
{
Stream stream = media.GetMediaStream();
byte[] buffer = new byte[1024];
int count = stream.Read(buffer, 0, 1024);
while (count > 0)
{
file.Write(buffer, 0, count);
count = stream.Read(buffer, 0, count);
}
}
return fileName;
}

protected void ReplaceFileInSitecore(string fileName, MediaItem mediaItem)
{
Media media = MediaManager.GetMedia(mediaItem);
using (FileStream stream = new FileStream(fileName, FileMode.Open))
{
media.SetStream(stream, "docx");
}
}



Want to learn more?

Monday, May 24, 2010

Browser Settings for Sitecore

I am a big fan of using a virtualized development environment (I use VirtualBox). By running everything in a virtual machine, it's much easier to test systems, upgrade software, and keep my laptop from getting cluttered. For me, the greatest advantage of working in a virtual machine is that I can easily roll-back changes I've made.

But working in a virtual machine has resulted in me installing a lot more software than I would have otherwise. Today, most installers are pretty streamlined and don't require much more than a little patience.

Sometimes steps are required that cannot be handled by an installer and must be performed manually. One of my least favorite of these is Internet Explorer configurations.

Sitecore recommends Internet Explorer be configured in a certain way. The Internet Explorer Configuration Reference available on SDN explains how and why.

The following code can be copied into a reg file and run in order to set the browser settings recommended in the SDN reference. I'm including this information for demonstration purposes only. Use at your own risk.

UPDATED: 09/17/2010 - Certain revisions of Sitecore 6.2 and 6.3 may be easier to navigate if the option "allow script-initiated windows without size or position constraints" is disabled. The settings below set that value to enabled.

======
Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\2]
"2001"=dword:00000000
"2004"=dword:00000000
@=""
"DisplayName"="Trusted sites"
"PMDisplayName"="Trusted sites [Protected Mode]"
"Description"="This zone contains websites that you trust not to damage your computer or data."
"Icon"="inetcpl.cpl#00004480"
"LowIcon"="inetcpl.cpl#005424"
"CurrentLevel"=dword:00000000
"Flags"=dword:00000043
"1200"=dword:00000000
"1400"=dword:00000000
"2007"=dword:00010000
"MinLevel"=dword:00010000
"1A10"=dword:00000001
"1001"=dword:00000001
"1004"=dword:00000003
"1201"=dword:00000003
"1206"=dword:00000003
"1207"=dword:00000000
"1208"=dword:00000000
"1209"=dword:00000003
"120A"=dword:00000003
"120B"=dword:00000000
"1402"=dword:00000000
"1405"=dword:00000000
"1406"=dword:00000003
"1407"=dword:00000000
"1408"=dword:00000000
"1409"=dword:00000000
"1601"=dword:00000000
"1604"=dword:00000000
"1605"=dword:00000000
"1606"=dword:00000000
"1607"=dword:00000003
"1608"=dword:00000000
"1609"=dword:00000000
"160A"=dword:00000000
"1800"=dword:00000001
"1802"=dword:00000000
"1803"=dword:00000000
"1804"=dword:00000000
"1809"=dword:00000003
"1A00"=dword:00020000
"1A02"=dword:00000000
"1A03"=dword:00000000
"1A04"=dword:00000003
"1A05"=dword:00000001
"1A06"=dword:00000000
"1C00"=dword:00010000
"2000"=dword:00000000
"2005"=dword:00000000
"2100"=dword:00000000
"2101"=dword:00000000
"2102"=dword:00000000
"2103"=dword:00000000
"2104"=dword:00000000
"2105"=dword:00000000
"2106"=dword:00000000
"2200"=dword:00000003
"2201"=dword:00000000
"2300"=dword:00000001
"2301"=dword:00000003
"2400"=dword:00000000
"2401"=dword:00000000
"2402"=dword:00000000
"2600"=dword:00000000
"2700"=dword:00000000
"TemplateIndex"=dword:00011000
"1806"=dword:00000001
"2500"=dword:00000003



======