fredag den 19. december 2014

Creating media items from a .NET Stream

From time to time, we need to create media items from .NET Stream objects (mostly when a user has uploaded a file).

In this case, this little helper function makes it really easy.

The parentItem is the parent item where them media item should be created below.
The fileName is the name of the file, including the file type (like "test.txt").
The contentStream is the stream containing the file content.
The fileBased bool defines if the mediaItem should be stored in the database or in the filesystem.

public static MediaItem CreateMediaItemFromStream(Item parentItem, string fileName, Stream contentStream, bool fileBased)
{
    if (parentItem == null)
    {
        throw new ArgumentNullException("parentItem", "parentItem must not be null.");
    }

    if (string.IsNullOrEmpty(fileName))
    {
        throw new ArgumentException("fileName must not be empty", "fileName");
    }

    // Just in case forwardslash is used, we replace it with backslash, before we do the test.
    string newMediaItemName = fileName.Substring(0, fileName.LastIndexOf('.')).Replace('/', '\\');

    if (newMediaItemName.Contains("\\"))
    {
        // We end here, if the file is uploaded using an ASP.NET FileUpload control, and the IE setting
        // "Include local directory path when uploading files to a server" is enabled.
        // Then we have to remove everything up till the last backslash, to get the filename.
        newMediaItemName = newMediaItemName.Substring(newMediaItemName.LastIndexOf('\\') + 1);
    }

    MediaCreatorOptions md = new MediaCreatorOptions
    {
        Database = DatabaseHelper.MasterDatabase,
        Destination = string.Format("{0}/{1}", parentItem.Paths.FullPath, ItemUtil.ProposeValidItemName(newMediaItemName)),
        FileBased = fileBased,
        IncludeExtensionInItemName = false,
        Versioned = false
    };

    using (new SecurityDisabler())
    {
        return MediaManager.Creator.CreateFromStream(contentStream, fileName, md);
    }
}

This also handles files being uploaded from Internet Explore, when it sends it's entire file path instead of just the file name.

torsdag den 18. december 2014

The case with the ASP.NET worker process being terminated from time to time

So, the other day we ran into an interresting issue, where a customers solution was crashing the entire worker proces.

Every time this happened, a few seconds before the Sitecore log file ended - this error showed up:

5784 10:41:07 ERROR Unhandled exception detected. The ASP.NET worker process will be terminated.
Exception: System.UnauthorizedAccessException
Message: The current user does not have write access to this item. User: sitecore/Anonymous, Item: Home ({71B4ACD7-226F-47A6-913D-86A40C0F9EBC})
Source: Sitecore.Kernel
at Sitecore.Data.Items.ItemEditing.BeginEdit()
at Sitecore.Data.Engines.TemplateEngine.<>c__DisplayClass3.b__0()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()

It seem to be related to publishing some item based on a certain template.
After a while, with the help from Sitecore Support, we found the issue - it seemed one of the templates (the one the items being published was based on) was inheriting the same template twice.

This is not normally possible (you cannot select the same item multiple times in a multilist field in Sitecore) - so the field's raw value had to have been manipulated somehow.

After removing the double inheritance, it started working without any issues.
So if you run into this issue, take a look at your template inheritance - the problem might be hidden there :-)