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.