Wednesday, October 19, 2011

Tridion Publisher and Custom Resolvers

Back in the day, we used to disable Tridion's link resolving (aka "Link Propagation") at publish time by using the old and venerable Event System (for more details about link resolving, check this page).

Recently I had to write some code to disable link resolving only under certain conditions for Tridion 2009, and started going down the true-and-tried road of Event System and "OnComponentPublishPre" events. Shortly after deployment in the test environment we started getting some really angry error messages from COM saying that my code was trying invalid casts.

Obviously offended by the suggestion that my code wouldn't work, I tried to understand what the **** was going on, and eventually figured out that it was all down to this: MSXML cannot be used in .NET code. And since the Event System in pre-2011 days is still based on COM and the Publish Instruction is an MSXML document... it would never work.

I could have re-written my Event System in VB6... but let's not even go down that path.

After scratching my head for about half a second, and some nudging from @puf on the right direction, I decided to try writing a Custom Resolver for the Tridion Publisher.

And I was so amazed with the results that I thought I should share it with you.

There's quite a few differences between a Custom Resolver and the Event System approach, the main ones being that you write your code in native .NET (using TOM.NET objects) and that you do not completely disable link resolving - you just fiddle with the results instead.

Another great advantage of a Custom Resolver is that it is forwards-compatible: the code you write for Tridion 5.3 or 2009 will also work with Tridion 2011(*).

So, let's get to the code, shall we?

Create a class library, add references to Tridion.Common, Tridion.ContentManager and Tridion.ContentManager.Publishing.

Create a class that implements the Tridion.ContentManager.Publishing.Resolving.IResolver interface.

Create a void method as follows:
public void Resolve(IdentifiableObject item, ResolveInstruction instruction, PublishContext context, Tridion.Collections.ISet <ResolvedItem> resolvedItems)

The resolvedItems collection is exactly what it looks like: this is the list of items that will be published unless we interfere with it. It's just a collection, so feel free to iterate through it, determine its type, remove items from it, etc. There's a reasonably good sample on the Tridion docs, just search for Custom Resolver.

Just a few more words on the deployment:
  • The assembly you create must go into the GAC
  • You have to add your assembly to the Tridion.ContentManager.Config file in the "resolvers" section AFTER the default resolver from Tridion
  • Restart the publisher and you're in business

(*) Hotfix CM_2011.0.1.74870 required in this pre-Service Pack 1 world.

7 comments:

Nivlong said...

Nice potential for scenarios with lots of linked components on XML-as-content pages (especially when multimedia components are rendered with publish binary).

Thanks for the post, Nuno!

Neil said...

Great post, but I'd be interested to know more about the scenario(s) that required link resolving to be disabled.

Its something I've never had to do (yet!).

Cheers

Nuno said...

You should only disable it if 1) you know what you're doing and 2) you really have a publishing bottleneck.

In this customer's scenario we actually check a whole set of conditions before turning link resolving off - but I've seen many implementations where it is always off (which I don't agree with).

N

Elena S said...

Thanks Nuno, good info. Also good to know is that the custom resolver code can be traced through for debugging purposes. So to debug while publishing, in Visual Studio developers can use the Attach to Process feature available under Debug top menu option and attach to both TcmPublisher.exe and dllhost.exe. Set breakpoints, trigger an item to publish and granted execution flow encounters one of the breakpoints.. voila, it stops and tracing is possible.

Anonymous said...

Thanks for the good post. I have a question though; why should we use the GAC for this and can't we use the (Tridion) bin folder?

Nuno said...

Hey Wouter,

Good question. I guess I used the GAC because it works, and it's what is mentioned in the documentation (and I'm one of those people that doesn't mind putting stuff in the GAC). If it works for you to have in the [Tridion]\bin, then by all means, go ahead and use it :)

Nivlong said...

Wait, this is resolving, not rendering component presentations. Ahhh. My first comment (back in 2011, whoa) was backwards.