5

I'm trying to create Multimedia Component in Event System, but it fails when saving new Multimedia Component.

My Event System program does following operation.

  1. When Multimedia Component is saved, event handler starts.

  2. Get binary content from the saved Multimedia Component, then generate thumbnail image file

  3. Create new Multimedia Component with the thumbnail image file.

How does this error occur? How can I create new Multimedia Component in Event System?

Error message and Event System source code is following.

Exception occures SetThumbnail.

The transaction associated with the current connection has completed but has not been disposed. The transaction must be disposed before the connection can be used to execute SQL statements.

at System.Data.SqlClient.SqlInternalConnectionTds.CheckEnlistedTransactionBinding() at System.Data.SqlClient.TdsParser.TdsExecuteRPC(_SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, Boolean isCommandProc)

at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)

at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)

at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)

at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()

at Tridion.ContentManager.Data.AdoNet.Sql.SqlDatabaseUtilities.SetBinaryContent(Int32 binaryId, Stream stream)

at Tridion.ContentManager.Data.AdoNet.ContentManagement.ItemDataMapper.Tridion.ContentManager.Data.ContentManagement.IItemDataMapper.SetBinaryContent(Stream stream, TcmUri id)

at Tridion.ContentManager.ContentManagement.RepositoryLocalObject.SetBinaryContent(BinaryContent binaryContent)

at Tridion.ContentManager.ContentManagement.Component.OnSaved(SaveEventArgs eventArgs)

at Tridion.ContentManager.IdentifiableObject.Save(SaveEventArgs eventArgs)

at Tridion.ContentManager.ContentManagement.VersionedItem.Save(Boolean checkInAfterSave)

public static void SetThumbnail(Component component)
{
    if (IsDownloadFileComponent(component))
    {
        ItemFields metaFields = new ItemFields(component.Metadata, component.MetadataSchema);
        MultimediaLinkField thumbnailField = (MultimediaLinkField)metaFields[ThumbnailFieldName];
        if (thumbnailField == null || thumbnailField.Value == null)
        {
            // Generate thumbnail image
            BinaryContent content = component.BinaryContent;
            string tempFileName = Path.GetTempFileName();
            FileInfo tempFile = new FileInfo(tempFileName);
            tempFile.MoveTo(tempFile.DirectoryName + "\\" + content.Filename);
            FileStream fileStream = null;
            Bitmap thumbnail = null;
            try
            {
                fileStream = tempFile.OpenWrite();
                content.WriteToStream(fileStream);
                fileStream.Close();
                fileStream = null;
                ShellFile shellFile = ShellFile.FromFilePath(tempFile.FullName);
                thumbnail = shellFile.Thumbnail.ExtraLargeBitmap;
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Close();
                    fileStream = null;
                }
                tempFile.Delete();
            }

            if (thumbnail != null)
            {
                thumbnail = GetResizedBitmap(thumbnail, int.Parse(ThumbnailWidth), int.Parse(ThumbnailHeight));

                // Create new multimedia component
                Component multimedia = new Component(component.Session, component.OrganizationalItem.Id);
                multimedia.Title = component.Title + ThumbnailSuffix;
                multimedia.Schema = GetDefaultMultimediaSchema(component);
                multimedia.BinaryContent.MultimediaType = GetMultimediaType(component);

                MemoryStream resizedStream = new MemoryStream();
                switch (multimedia.BinaryContent.MultimediaType.MimeType.ToLower())
                {
                    case "image/png":
                        thumbnail.Save(resizedStream, ImageFormat.Png);
                        multimedia.BinaryContent.UploadFromStream = resizedStream;
                        multimedia.BinaryContent.Filename = Path.GetFileNameWithoutExtension(content.Filename) + ThumbnailSuffix + ".png";
                        break;
                    case "image/jpg":
                    case "image/jpeg":
                        ImageCodecInfo jpegEncoder = GetEncoderInfo(multimedia.BinaryContent.MultimediaType.MimeType);
                        EncoderParameters encParams = new EncoderParameters(1);
                        encParams.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
                        thumbnail.Save(resizedStream, jpegEncoder, encParams);
                        multimedia.BinaryContent.UploadFromStream = resizedStream;
                        multimedia.BinaryContent.Filename = Path.GetFileNameWithoutExtension(content.Filename) + ThumbnailSuffix + ".jpeg";
                        break;
                    case "image/gif":
                        thumbnail.Save(resizedStream, ImageFormat.Gif);
                        multimedia.BinaryContent.UploadFromStream = resizedStream;
                        multimedia.BinaryContent.Filename = Path.GetFileNameWithoutExtension(content.Filename) + ThumbnailSuffix + ".gif";
                        break;
                    case "image/bmp":
                        thumbnail.Save(resizedStream, ImageFormat.Bmp);
                        multimedia.BinaryContent.UploadFromStream = resizedStream;
                        multimedia.BinaryContent.Filename = Path.GetFileNameWithoutExtension(content.Filename) + ThumbnailSuffix + ".bmp";
                        break;
                    default:
                        string message = "This MIME type is not supported : " + multimedia.BinaryContent.MultimediaType.MimeType;
                        throw new Exception(message);
                }

                multimedia.Save();
                thumbnailField.Value = multimedia;
                component.Metadata = metaFields.ToXml();
            }
        }
    }
}
2
  • +1 for the question, Hirokazu. An Event System approach is perfect when authors need control after the thumbnails are created. But also consider if creating these during publish (in template code) using what Tridion calls image variants (see AddBinary() in the TOM.NET documentation) makes sense for the authors. Commented Jul 16, 2013 at 23:48
  • What is the status of this question, was @Nuno's answer helpful? Commented Jul 18, 2013 at 13:22

1 Answer 1

2

It could be that this is the result of a Timeout (the error message is the same IIRC). Tridion Events are not allowed (by default) to take longer than 30 seconds. You could try:

  • Changing your event logic to run asynchronously instead of synchronously (EventSystem.SubscribeAsync)
  • Increasing your event timeout (in Tridion.ContentManager.Config)

Unless your images are massive, I wouldn't expect something like this to take very long - a couple of seconds at most - so perhaps it's not a timeout.

Could you be stuck in an "Event Loop"? Saving a component in the event system will trigger the Save event for this new component, which in turn will Save a new component which in turn will trigger the Save event, etc.

2
  • This issue is not solved yet. But I wrote a mistaken comment in first question.The Event Sytem code doesn't create thumbnail image file, only using MemorySteam. I found that if using a image file, it is no problem. So problem is, how it fails when using only MemoryStream, not image file. Commented Jul 19, 2013 at 11:25
  • Interesting. The documentation does state that UploadFromStream "can be set to any standard Stream object", so a MemoryStream should work.
    – Nuno Linhares
    Commented Jul 19, 2013 at 13:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.