I was recently working on an implementation which required a custom Deployer Module to publish and un-publish DCPs from a third party system. In order to store and retrieve data in/from the system, certain ‘non-display’ data is required by the Deployer (think configurable username, passwords, and primary keys for the databases etc.).
Publishing actions were very straight forward, as all of the ‘non-display’ data could be stored in the contents of the DCP and parsed out before storing it. There are even more elegant ways of adding Metadata to Publish Instructions. Unfortunately this is not the case for a un-publish action. The only information sent in the package when un-publishing a DCP is an instruction to remove the specific DCP (or DCPs).
Having never faced this challenge before, I posted the question on tridion.stackexchange.com and received a suggestion from Eric Huiza regarding an un-documented extension point for the transport package called a TransportPackageHandler. I will leave it to you to decide if it is a great suggestion or not.
This post attempts to explain my discoveries regarding this extension point, and at least to start making it “documented”.
Documenting the un-documented
Now, “un-documented” is a pretty key word here, as it probably means that it is also not “supported”, and the interface could easily change in the future. That said, I have yet to find an officially documented/supported way of sending instructional data to a Deployer when un-publishing any item from Tridion’s presentation layer (any suggestions would be appriciated).
Interestingly, back in the late 90’s when Tridion R3 was written with Pearl modules, templates actually consisted of both publish and un-publish code which was executed depending on the action being performed, and you could do exactly what I am trying to do here.
By posting this article I am certainly not suggesting that this is a good or advisable approach (at least until this becomes an officially supported extension point), but I figured I would share what I found (with a lot of help from Eric).
High level concepts of a Transport Package Handler
A Transport Package Handler is very simply a Class which implements the Tridion.ContentManager.Publishing.Transporting.ITransportPackageHandler interface. The interface has 3 methods for handling publishing and un-publishing items. Specifically for my challenge, I am looking at extending the behavior of the HandleResolvedItemForUnPublishing method.
The Handler is invoked by the Publisher Service when it is done resolving (and rendering in the case of a publish action) before it actually assembles the contents of the package. The resulting data is then zipped up into a Transport Package before the Transport Service sends it to the Content Delivery side of the Tridion Architecture.
The TransportPackageHandler is configured in the <transporting/> element of theTridion.ContentManager.config file, which stores mappings for each publishable item type. To add a new handler to an item type (in my case a handler for the Item type Tridion.ContentManager.ContentManagement.Component) you will need to strongly name your assembly, and add it to the GAC (see my note to self at the bottom if you don’t know how to do this).
Unfortunately, as of SDL Tridion 2013 GA, the transport mappings only support one handler per item type. So you will need to comment out the default handlers that you wish to extend. This effectively means that you have to re-implement the default handlers from your new code if you want to add to the out-of-the-box offering rather than replace it. To add to this frustration, the default classes are not marked as virtual, so you can’t actually inherit and override them. There are several approaches to this, but below is my starting point which implements the default component handler functionality from which I will build my new extension.
To get around this lack of inheritance, I simply invoke the default handler for the ItemType (DefaultComponentHandler) I am extending.
Extending the HandleResolvedItemsForUnPublishing method
Once the class is setup, it is pretty easy to implement your own behavior. The following is a very simple example. The code checks the namespace of the resolved component’s schema, and if there is a match, it adds a custom node to the instructions XML.
This code results in the following XML
To run your code in debug, remember the following steps:
- Rebuild your DLL
- Make sure your handler is configured using the public token in the Tridion.ContentManager.config file
- Run GacUtil.exe to make sure the latest copy of your DLL is in the GAC
- Restart your Publisher Service
- Attach your debugger to the TcmPublicher.exe process and add a breakpoint
- Un-publish an item which must already be published to the same target you are un-publishing from (otherwise your item will not get resolved, and the handler will not be invoked)
- Debug away…
This seems to be a great extension point, and does exactly what I needed. There are a few quirks (i.e. lack of inheritance or support for chaining handlers together like you can with Resolvers), but on the whole it works really well. However, please keep the following points in mind:
- This is not currently supported (as far as I know)
- Make sure you implement all of the default behavior, otherwise you will mess up all of your publishing/un-publishing actions (basically empty instructions XML files and no items being added to your transport packages)
- Your code is executed on every publish/un-publish action, so be sure to check the publications, schemas and templates etc., otherwise you could damage the performance of the publisher, and needlessly add/remove data from publish/un-publish actions
- Remember that the Handler methods are called for each item in a PublishTransaction, so be careful not to add duplicate data (i.e. if you publish a component which has multiple dynamic DCPs, then my code would add a new <UrbanCherryInstruction/> element for each DCP
So if you like the idea, please consider nudging your favorite SDL contact person to have this added as a valid extension point (or go and vote on it at ideas.sdltridion.com).
NOTE TO SELF: Strongly named assemblies in the GAC
In order to strongly name an item for the GAC (I always forget this, so this is really just a reminder for myself), follow these steps:
- Add a strong name key to your assembly from the properties of your project. I typically create a new one for each DLL.
- Build your DLL, and note down the location of the file
- Using Developer Command Promt for Visual Studio, navigate to the folder where your assembly was built and type > sn.exe -T <AssemblyName> to get the public key token of your new assembly (This is used in the Tridion.ContentManager.config file above).
- Still in Developer Command Promt for Visual Studio type> gacutil.exe -i <AssemblyName> to place your DLL in the GAC
- If you don’t have GacUtil on your higher environments (Dev, Test, Acceptance and Prod etc.), it is highly recommended to create an installer to insert your code into the GAC.