9

We have the following scenarios and want to achieve them without using events (probably using TBB’s or extensions if possible). I have not gotten much help from the forum, please suggest and share some links or ideas if possible.

On the event OnPagePublishPost the following functionality is in place:

  1. For each Publisher Request (PublisherRequest/PublisherResponse) it gets the list of tcm ids from the sys config component.
  2. It gets the actual Publication target id and publish priority required for the Publish/Unpublish action
  3. For each component presentation it checks if the schema id is matched with the tcmids (from sys config)
  4. It gets the component (from the component's tcm id) and if it is based on a dynamic schema (match found), publishs the component so that all dynamic component presentations are published/unpublished to/from the Broker depending on the action performed on the page.

Can you suggest a way this can be achieved without using an event system call? Can we achieve this using TBB/Templates/Extensions?

The following functionality is in place on OnComponentSavePre Event calls:

  1. It checks for TCM uris from the system configuration component for both "news_article_schema" and "product_schema".
  2. Then, it compares the component's (passed as a parameter) schema id with the TCM URI.
  3. If the schema id is of "news_article_schema", the the component field "publication_date" value to the component's metadata field "year".
  4. If the component is of Multimedia type, then it checks the value for the component's metadata field "filesize" and formats the value based on on different conditions.

Is it possible to achieve the same functionality without an event call using tbbs/extensions?

3
  • What do you mean by a Dynamic Schema? Commented May 7, 2013 at 10:08
  • what version of SDL Tridion are you using and would it be an option to upgrade to the latest version? Commented May 7, 2013 at 16:09
  • Welcome to the Tridion Stack Exchange Site! I have edited your question to clarify some of the points you were asking about. If you disagree with any of my edits please feel free to revert them back to the previous version. Commented May 8, 2013 at 5:11

4 Answers 4

9

To add to Nuno's answer, indeed using the COM based event system through .NET has a lot of potential (memory related) issues if not done correctly. I always use the following code examples to explain what needs to be done:

using System;
using Tridion.ContentManager.Interop.TDS;
using Tridion.ContentManager.Interop.TDSDefines;

namespace Tridion.Training.Samples
{
    public sealed partial class Program
    {
        public static void Main(string[] args)
        {
            TDSE tdse = new TDSE();
            tdse.Impersonate(@"domain\user");
            tdse.Initialize();

            Component comp = (Component)tdse.GetObject("tcm:1-234",
                                                       EnumOpenMode.OpenModeEdit);
            if (comp != null)
            {
                Console.Out.WriteLine(comp.Info.Creator.Name);
            } 
        }
    }
}

Now this is a typical example of how to use SDL Tridion TOM objects in .NET, with the problem being that the System resources of TOM objects are not released. So consider the following bit of code:

using System;
using System.Runtime.InteropServices;
using Tridion.ContentManager.Interop.TDS;
using Tridion.ContentManager.Interop.TDSDefines;

namespace Tridion.Training.Samples
{
    public sealed partial class Program
    {
        public static void Main(string[] args)
        {
            TDSE tdse = new TDSE();
            tdse.Impersonate(@"domain\user");
            tdse.Initialize();

            Component comp = (Component)tdse.GetObject("tcm:1-234",
                                                       EnumOpenMode.OpenModeEdit);
            if (comp != null)
            {
                Console.Out.WriteLine(comp.Info.Creator.Name);
                Marshal.ReleaseComObject(comp);
            }
            Marshal.ReleaseComObject(tdse);
        }
    }
}

The problem with this code is that still there are System resources, through lazy loading TOM Info and User objects, that are not released properly. So lets take care of that:

using System;
using System.Runtime.InteropServices;
using Tridion.ContentManager.Interop.TDS;
using Tridion.ContentManager.Interop.TDSDefines;

namespace Tridion.Training.Samples
{
    public sealed partial class Program
    {
        public static void Main(string[] args)
        {
            TDSE tdse = new TDSE();
            tdse.Impersonate(@"domain\user");
            tdse.Initialize();

            Component comp = (Component)tdse.GetObject("tcm:1-234",
                                                       EnumOpenMode.OpenModeEdit);
            if (comp != null)
            {
                Info info = comp.Info;
                User creator = info.Creator;

                Console.Out.WriteLine(creator.Name);

                Marshal.ReleaseComObject(creator);
                Marshal.ReleaseComObject(info);
                Marshal.ReleaseComObject(comp);
                Marshal.ReleaseComObject(tdse);
            }
        }
    }
}

Okay better, but still a problem with System resources of TOM objects that are not released in case of runtime exceptions. Next try:

using System;
using System.Runtime.InteropServices;
using Tridion.ContentManager.Interop.TDS;
using Tridion.ContentManager.Interop.TDSDefines;

namespace Tridion.Training.Samples
{
    public sealed partial class Program
    {
        public static void Main(string[] args)
        {
            TDSE tdse = null;
            Component comp = null;
            Info info = null;
            User creator = null;

            try
            {
                tdse = new TDSE();
                tdse.Impersonate(@"domain\user");
                tdse.Initialize();

                Component comp = (Component)tdse.GetObject("tcm:1-234",
                                                           EnumOpenMode.OpenModeEdit);
                if (comp != null)
                {
                    info = comp.Info;
                    creator = info.Creator;

                    Console.Out.WriteLine(creator.Name);
                }
            }
            finally
            {
                if (creator != null) { Marshal.ReleaseComObject(creator); }
                if (info != null) { Marshal.ReleaseComObject(info); }
                if (comp != null) { Marshal.ReleaseComObject(comp); }
                if (tdse != null) { Marshal.ReleaseComObject(tdse); }
            }
        }
    }
}

We are almost there, one problem left, Marshal.ReleaseComObject can throw runtime exceptions. Let's finalize all that in the last example:

using System;
using System.Runtime.InteropServices;
using Tridion.ContentManager.Interop.TDS;
using Tridion.ContentManager.Interop.TDSDefines;

namespace Tridion.Training.Samples
{
    public sealed partial class Program
    {
        public static void Main(string[] args)
        {
            TDSE tdse = null;
            Component comp = null;
            Info info = null;
            User creator = null;

            try
            {
                tdse = new TDSE();
                tdse.Impersonate(@"domain\user");
                tdse.Initialize();

                Component comp = (Component)tdse.GetObject("tcm:1-234",
                                                           EnumOpenMode.OpenModeEdit);
                if (comp != null)
                {
                    info = comp.Info;
                    creator = info.Creator;

                    Console.Out.WriteLine(creator.Name);
                }
            }
            finally
            {
                ReleaseCom(creator);
                ReleaseCom(info); 
                ReleaseCom(comp); 
                ReleaseCom(tdse); 
            }
        }

        private static void ReleaseCom(object instance)
        {
            if (instance != null)
            {
                try
                {
                    Marshal.ReleaseComObject(instance);
                }
                catch
                {
                    /* log potential memory leak */
                }
            }
        }
    }
}

As you can see if you ignore proper handling, there are a lot of options for you to create potential memory leaks when using COM.

10

From the title of your question "Event System Alternatives (Memory Leakage)", it appears that you may be looking for alternatives to using the Event System due to a memory leak that you have in some existing code. If this is the case, then I would strongly recommend that you fix the source of the memory leak problem, rather than finding workarounds.

That said....

Scenario 1: If I have understood it fully, then if a Component on a Page can also be used in a Dynamic Component Presentation (i.e. There is a 'Dynamic Component Template' that is associated with its Schema) and it is 'in the list', then the Dynamic Component Presentation (DCP) is also published (along with the page).

If this is the case, then you could use a Custom Resolver to ensure that these Components also get published dynamically.

Scenario 2: This really depends on what you are trying to achieve...

If the values in the 'publication_date' and 'filesize' only affect the published content, and do not need to update the content when the Component is saved, then you could do this in templating code. You should be able to do this easily using Razor Templating (with a helper method for doing the filesize logic possibly) or using the Dreamweaver Get eXtension.

As a cautionary note, I suspect that your 'year' field is not really necessary and that this is just a replication of the information stored in the 'publication_date' field. If that is true, then you should consider moving the 'publication_date' field in to the Metadata (assuming that it is used to filter/sort on) and updating your content delivery code to reflect this (now being a full DateTime field).

1
  • +1 to the scenarios. Also for #1, authors might also be able to control what gets published. By default dynamic component presentations are published when a page that uses them is published. Publishing a component that has a dynamic component template won't typically publish pages their on unless they're "statically" embedded on those pages. #2 does sounds like a good templating candidate--basically for the template that handles news_article_schema, use the same value for publication_date and year. If needed for custom_meta, for the given schema also use the same field. Commented May 7, 2013 at 23:50
7

Given the event names, I assume you're on Tridion 2009 and COM-based events.

I have worked many times with COM-based event systems, and the key aspect for memory usage is to understand that Microsoft lied. COM objects are really easy to link to from .NET, but due to them being unmanaged, the .NET runtime doesn't really clear them when it should.

To ensure your objects are released from Memory once they are not needed anymore you must invoke Marshall.ReleaseComObject for each object instance that you create.

4

For 1: You can use following methods:

  1. Use the Deployer Extension (in Java) and you should be able to achieve whatever you have explained above. Moreover, it will get invoked for Dynamic Component Presentations, so may be you can avoid checking for dynamic component presentation.
  2. Create a Custom Processor (in Java) for processing your deployer request

It may make more sense to suggest more solutions if you can share your requirement instead of the algorithm (which is a bit unclear like what you want to do with the information retrieved in step 3)

For 2 For this scenario, apart from Event System, I can not think of any other extension point to achieve this. (Other members may add their knowledge if there are any other innovative ways)

2
  • Image changes based on size might be a good case for "variants." Commented May 7, 2013 at 23:53
  • 1
    We have already tried with Marshall.ReleaseComObject for each objects but, still it is occuring very frequently. Please suggest. Thanks for your help. Commented Jun 26, 2013 at 12:44

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.