Create your own Global Events

Part of what makes any CMS worth its salt is the ability to extend its functionality.  Kentico has done this through Global Event hooks, which allow you to intercept and modify the behavior of the internal workings at certain key points.  All the Info objects inherit this and have an Insert/Update/Delete Before/After event hooks, and on top of that Kentico offers many other custom hook points.

All of these use a couple base Kentico classes that handle the creation and delegation of these events, and since these classes aren’t hidden away, that means we can leverage them as well to make our custom modules easily extensible.

If you are creating a marketplace submission, or even an internal module that you plan on using on multiple sites, global events are probably something you’re going to benefit from.

Flexibility vs. Complexity

The more flexible a tool is, the more places it can be used.  However, this usually comes at a big cost, and that cost is complexity.  Trying to imagine all the different use cases, the different scenarios, and coding in logic to handle all of those can be a nightmare, and ultimately you can never truly account for EVERY scenario.

However, by adding in some custom event hooks, you can allow individuals who use this tool to modify it just how they need it, in their own unique situations.  This is the beauty of the event hook system. 

Setting up the Event

Creating a custom event is quite simple:
  1. Create your CMSEventArgs class (event properties)
  2. Create your EventHandler
  3. Create your Event Class
Let’s look at the code for each, I’ll be using the DynamicRoutingEvents.GetPage as an example.

Create your CMSEventArgs class

The first step is to decide what you’ll pass to the Events.  This can be any class you wish but should contain any data the user may need to perform relative actions.  This class must inherit from CMSEventArgs for Kentico to allow it to be used. 

Failed to load widget object.
The file '/CMSWebParts/Custom/HighlightJS/HighlightJS.ascx' does not exist.

Create your EventHandler

The next step is to create your Event Handler class.  This needs to inherit the AdvancedHandler<YourEventHandler, YourEventArgs> class.  The only thing worth mentioning on this is since the base Finish method is hidden, you need to add your own Finish Event to call this, which triggers the After event.

Failed to load widget object.
The file '/CMSWebParts/Custom/HighlightJS/HighlightJS.ascx' does not exist.

Create your Event Class

The Last step is to create a static class that will expose your handler, making it easy for the user to add their own hooks to it.  Just follow the below example’s format.

Failed to load widget object.
The file '/CMSWebParts/Custom/HighlightJS/HighlightJS.ascx' does not exist.

Leveraging the Event in our Code

Now that we created our event, let’s go through using it in our code, using this outline:
  1. Create your Event Argument
  2. Initialize the Event (Before Event triggered)
  3. Perform your normal logic (possibly considering if the user used the Before trigger)
  4. Call the Finished method (After Event triggered)
  5. Finish your logic/method.
We’ll summarize and then go into detail on each step.  We will be using the example of my DynamicRouteHelper.GetPage() method, which leverages the DynamicRoutingEvents.GetPage event.

1: Create your Event Argument

The first step is to create and populate your EventArgs class.  This will be passed to the Before event, and will give the user the information they need, and possibly also properties they may need to modify in order to customize.

Failed to load widget object.
The file '/CMSWebParts/Custom/HighlightJS/HighlightJS.ascx' does not exist.

2: Initialize the Event

Next is to Initialize the event itself by creating a new instance of your EventHandler (using a using block is probably preferable in this case).  The act of creating a new instance automatically will trigger the Before event, which allows the users to customize.

Failed to load widget object.
The file '/CMSWebParts/Custom/HighlightJS/HighlightJS.ascx' does not exist.

3: Perform your normal logic

At this point, now you must decide what to do.  You should account for anything the user may have done in their hook and adjust accordingly.  For the GetPage() method, I do a check to see if the TreeNode is null or not, if it is not null then the user must have found the page already in their implementation, so I don’t need to do my default logic of trying to find the page myself.  But if it is null, then I need to perform my normal logic to try to get the current page based on the UrlSlugs.  How you leverage your arguments will be up to you of course, this is just an example:

Failed to load widget object.
The file '/CMSWebParts/Custom/HighlightJS/HighlightJS.ascx' does not exist.

4: Call the After Event

Last step is to call the EventHandler’s Finished event, which will trigger the After event hook.  This should allow users another change to modify the results/behavior.  The current EventArgs are passed again to the After event hooks. 

Failed to load widget object.
The file '/CMSWebParts/Custom/HighlightJS/HighlightJS.ascx' does not exist.

5: Finish

Now that everything is complete, you can finish your action.  In my case, I’m returning the TreeNode found (either by my default logic, or the user’s intervention).

Leveraging the Global Event Hooks

Now that your event hooks I created and you have added it to your logic, others can hook into it.  Here’s just a sample of what it would look like for someone to modify the GetPage logic, in this case if the found page is the CMS.Root page (user hits just the domain), to replace it with the home page.

Failed to load widget object.
The file '/CMSWebParts/Custom/HighlightJS/HighlightJS.ascx' does not exist.


I hope this little guide will be helpful to all those who are working hard to help expand Kentico further.  Know I’ve implemented this in both the DynamicRouting and the Kentico Authorization modules, and plan on using this further in future tools as well.
Blog post currently doesn't have any comments.
Is six > than eight? (true/false)