An event, in any computer system, is an interruption in the current process. The computer is busy doing what it should be doing, and then something happens to stop it and send it in a different direction. In old systems this was limited to the user clicking a keyboard key or a mouse button. Now, with much more complex systems, it can include state changes, network events, new data, and nearly everything else.
The Tridion Event system had a major overhaul with Tridion 2011 and it looks unchanged with Tridion 2013 SP1. The event system attaches to the TOM.NET API which means that it reacts to events both within the Content Manager and within the core services.
Although the event system reacts to all manner of events (over 20 in total) we’ll look at examples that a content editor would see.
One key feature of the event system is that it has almost no user interface. You can’t ask the user a question, present an alert() dialog, or get them to re-type a phone number. It simply works in the background, validating data, generating reports, sending e-mails, etc. or it doesn’t. The user is never told when it works, rather they are only told when it doesn’t, and this is through a message in the Message Center.
Examples of events are:
- When you save a Publication, ensure that it has a parent publication. This ensures that you have only one root publication. It also reduces rework, since you can’t edit a root publication and add a parent later on.
- When you save a Page or a Publication, ensure that they have a Metadata Schema. This will help ensure system integrity if you rely on those schema fields.
- Fine tune user editing, for example allowing specific users to edit only certain Keywords. Out of the box, a user is either allowed to edit keywords in all categories, or they aren’t allowed to edit any keywords. With the event system, you have a simple way to say that a user can save changes or deletions of keywords within certain categories but not within others. Edit: That is – you can provide that functionality to fit a pattern of categories, for example all of those where the category name begins with “[Application]”, without having to set the security for each category.
This is real time error checking, at the system level. An alternative is to perform the check at publish time and then fail the publish. By that time the user has forgotten the context and so the rework cost is a lot harder. With the event system acting on a save or a delete, we tell the user what happened and how to correct it. It is top of mind for them.
The event handler is included in %TRIDION%\config\Tridion.ContentManager.config as:
<extensions> <add assemblyFileName="C:\Tridion Extensions\OnSaveValidation\OnSaveValidation.dll" /> </extensions>
and gets loaded when Tridion is started. The documentation says that you have to stop and restart both the Tridion Content Manager and COM+. I’ve found that it’s sometimes more than that.
When you are updating the deployed system or you are developing the code you have to stop Tridion , deploy the new code, and start Tridion. This can be handled, in the Visual Studio project, with the Pre-build and Post-build events. We use “start” before the “net stop” and “net start” commands to run them in a different process. If we try to stop a service and it’s already stopped then the “net stop” command will return an error. By having it in a separate process, that error is not returned to Visual Studio.
We set up the class, provide a unique TcmExtension name for the class, and set up the event calls in the constructor. These calls indicate how to handle an event — the how (Subscribe), what (Publication), generally when (SaveEventArgs), the handler (HandlerForSavePublication), and specifically when (Processed). In the example below, we are setting a Save event handler for a Publication, Page, and Keyword, and a Delete event handler for the Keyword. The second Keyword handler is because a Delete event is different from a Save event, and we want to restrict both.
The event handler can be called in two ways:
- EventSystem.Subscribe — happens when the event happens, and should be used most of the time.
- EventSystem.SubscribeAsync — happens at some point after the event, and should only be used on finalized data. That is, it should only be called following a Commit or an Abort event. If it’s called for an earlier event then the data may change by the time the event handler gets to it.
There are many different types of events. Some of them are:
There are five event phases:
- Initiated — The data has been received by the browser and has not been written to the server.
- Processed — The data has been written to the server but has not been committed. An exception will perform an abort and the data won’t be saved.
- TransactionAborted — The transaction was backed out.
- TransactionCommitted — The transaction has been committed.
- TransactionInDoubt — The transaction is in an unknown or unstable state. I can’t imagine a use case for this.
In this function we are loading the configuration information, determining if we should check for parents, and then checking if there are any parents (item.Parents.Count == 0). If there are no parents we throw an exception, which this shows up in the Message Center, and the data is not saved, rather it is rolled back.
When used for validating custom editing rules like this, the Event System:
- isn’t that hard to write for, although the code has to be very solid
- can make some tasks much easier by eliminating workflow
- provides immediate feedback and can show errors to the user where they expect and while they are still thinking about them
With the right planning, this can be the very best way to get some things done.
- From SDL
- From Rob Curlette
- From Alex