The story of SDL Tridion 2011 Custom Resolver and the allowWriteOperationsInTemplates attribute

Before I start with this blog, let me thank all those who have helped me find my way whilst stumbling around in the forest on this one, you know who you are. Had I read the release note properly over a year ago, I am sure I would never have made this journey, however I have learned a lot and figured I would share what I found.

A long, long time ago, in an office somewhere in the Netherlands I decided to make a VBScript Component Template for Tridion R5.0 which created the HTML for an article, and then published a summary DCP (Dynamic Component Presentation) for inclusion in a broker driven index page. I was a happy man.

Sometime later, I was at a client in Norway, and I only had rights to make templates and pages etc. My client needed me to create a new user in the CMS. The Tridion Administrator was on vacation, so I made a template that created a new user in the system. Again, I was a happy man.

A few years down the line I was building a photo gallery, and I needed to resize some images. This was pretty easy using Compound Templates, but I thought it would be nice to store the resized images as multimedia components to prevent having to do this every time I published the gallery, so I added code to my templates to create new components from the images and add their height, width and alt attributes to their metadata. Harmony gently rolled across my Tridion world.

Now in fairness, I have always known that this approach of using templates to manipulate items in the Content Manger may not have been a good practice, but sometimes I think we all resort to less than ideal methods and in some cases with older versions of Tridion we had little choice. But that was then, and this is now. My main motivate for using templates was that I could create code directly in the CMS, and did not need access to the CMS Server’s file system to install or register DLLs etc.

In March last year I installed SDL Tridion 2011 for another client, and I did not notice that “Write operations in Template code” were no longer allowed according to the release notes. However nothing broke, my templates still worked. The world remained a happy place.

Leaping forward to the present, I just installed SDL Tridion 2011 SP1in the client’s development environment and things got a little bit darker, that happy feeling started to slip away and a cloud swept in over my upgrade schedule. One of our main Page Templates (A compound PT which uses .NET assemblies written in c#) contains a line code similar to the following:

PublishEngine.Publish(
	new IdentifiableObject[] { linkedComponent },
	engine.PublishingContext.PublishInstruction,
	 new List() { engine.PublishingContext.PublicationTarget });

The goal of the code is to make certain binaries get published dynamically using a CT which places the binaries in specific secured directories (structure groups) on the web server. It seems that as of SP1, Publish actions are no longer considered ReadOnly. This is the only “non-ReadOnly” method we use in this implementation, which is why I have only discovered the restriction now rather than in the GA release.

So that is the background of the problem, and below I will try to share some workarounds (one good and and two bad).

Custom Resolvers

I was advised by SDL Customer Support that a better way to achieve my goal was to create a Custom Resolver. This was something I had never done before, but after some Google-ing plus some trial and error, I managed to make a strongly named DLL and place it in the GAC of my Publishing Servers based on the following example code:

using System;
using System.Text;
using Tridion.ContentManager.Publishing;
using Tridion.ContentManager.Publishing.Resolving;
using Tridion.ContentManager;
using Tridion.ContentManager.ContentManagement;
using Tridion.ContentManager.CommunicationManagement;
using Tridion.Collections;
using System.IO;

namespace UrbanCherry.Net.SDLTridion.CustomResolvers
{
    class DynamicBinaryLinkResolver : IResolver
    {
        public void Resolve(IdentifiableObject item, ResolveInstruction instruction, PublishContext context, ISet<ResolvedItem> resolvedItems)
        {
            if (!(item is Component))
            {
                return;
            }
            else
            {
                Component otherComp = (Component)context.Session.GetObject("tcm:235-49754");
                ComponentTemplate renderTemplate = (ComponentTemplate)context.Session.GetObject("tcm:7-81063-32");
                ResolvedItem newitem = new ResolvedItem(otherComp, renderTemplate);
                resolvedItems.Add(newitem);
            }
        }
    }
}

I then attached my Visual Studio Project to the TcmPublisher.exe process, and published a new component, and voila… I could step through my code, the new Dynamic Component Presentation was published, and the binaries ended up in the same places they had before my SP1 upgrade.

To further improve things, the dynamic component presentations were actually transported in the same publish transaction package as the original component, rather than being placed in the Publishing Queue and published later. The only real downside to this approach that I could see was needing to actually place a DLL on the server and modify the config files. From an administrative perspective this may be a change request which would need to be performed by a System Administrator on all the publisher machines in the Tridion Environment, rather than a simple change to a template uploaded to the CM database by a developer.

Alternative options

Now I believe the above solution is a great approach (possibly even a Best Pratice), in part because I am happy to have learned something new. However, for some other “Write Functionality” you may need to perform tasks that cannot be implemented as easily. Think about my photo gallery case above. For that I would probably now build an Event Handler which captures the ComponentSave event of the original multimedia component, then creates resized versions of the image, and saves them as new multimedia components.

There are similar hooks and techniques for almost any action you care to perform, but it does involve work and learning about new approaches and parts of the product. So before you read the next 2 options, I strongly suggest you figure out a good practice for doing what you want to do, and only use these options as a last resort.

Remember the improved security of the publisher having only read only access is designed to make the system more secure, and the following are really hacks which reintroduce some of the issues by unplugging the recently filled holes.

Create a new Privileged Session Object

This is probably the simplest, but it took some help from Customer Support and Tridion R&D to get it to work. The main reason that my original code didn’t work was that the Session used to load the object I wanted to publish is instantiated with read only permissions by the template engine.

You can create your own session and impersonate any user you like, but it took a while to figure out how to use the PublishEngine.Publish() method with the new session. It turns out, if you just load the item you want to publish using a privileged session, the action is allowed. The following code illustrates this

<br />
Session privilegedSession = new Session("domain\\PrivilegedTridionUser");<br />
Component privilegedLinkedComponent = (Component)privilegedSession.GetObject(linkedComponent.Id);<br />
PublishEngine.Publish(new IdentifiableObject[] { privilegedLinkedComponent }, engine.PublishingContext.PublishInstruction, new List<PublicationTarget>() { engine.PublishingContext.PublicationTarget });<br />

I have always understood it to be a bad practice to create new sessions in your templates, so I can’t recommend this as a good solution, but it explains what is going on behind the scenes.

Core Service

In theory you can call the core service from any code you like, and if you have the correct credentials, you can do anything you like with it. So you could create a CoreService2010Client, and use its methods to create and publish all you like from within a template. It some ways, this is safer than using the TOM.NET API as it forces the developer to explicitly create a client with specific credentials, but it could still result in a template executing hidden (and possibly malicious) code. This is really just making a new hole rather than unplugging the old one.

Override the security settings

The last option I have is probably the worst (as it completely unplugs the hole that was filled), so I am glad I only just discovered it. You can revert to the old Tridion2009 and older security policy by allowing templates to perform write actions. To achieve this you need to add an “allowWriteOperationsInTemplates” attribute to the security node in the Tridion.ContentManager.Config file as follows:

</p>
<tridion.contentmanager.security allowAutomaticUserCreation="true"<br />
    hideOrganizationalItemsNoAccess="false" allowWriteOperationsInTemplates="true"><br />
    <impersonationUsers><br />
      <clear /><br />
      <add name="NT AUTHORITY\NETWORK SERVICE" impersonationType="Windows" /><br />
      <add name="NT AUTHORITY\SYSTEM" impersonationType="Windows" /><br />
    </impersonationUsers><br />
  </tridion.contentmanager.security>

Summary

That’s all for now, I hope this helps some of you gain an understanding of the change and the possibilities of custom resolvers. I am now off to recreate my happy place by writing a full implementation of my new resolver, and will post the code once it is working in full.  

This entry was posted in Helpful Tridion tips, Tridion 2011, Tridion news and tagged , , , , , , by Chris Summers. Bookmark the permalink.

About Chris Summers

Chris has spent his career creating and developing technology for website operation and management. With a background in engineering and design, for the past 12 years, Chris has focused on implementing SDL Tridion products, working with companies and their technical staff to ensure an in-depth understanding of the software and complete successful, on-going implementations. Chris has worked with more than 60 of the largest and most expansive SDL Tridion implementations in the world, from launching custom integrations, offering technical training and mentoring consultants through to certification. When he’s not talking or thinking about websites, Chris is an avid chef, an amateur carpenter and a flying trapeze enthusiast. A fan of travel and adventure, he’s a citizen of the world who currently makes his home in Boston, USA.

4 thoughts on “The story of SDL Tridion 2011 Custom Resolver and the allowWriteOperationsInTemplates attribute

  1. Pingback: A Custom Resolver in practice | Tridion Developer

  2. Pingback: Cannot insert the value NULL into column error | XL-UAT

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>