Remote vs Local Custom Publishing Events in Sitecore
Sitecore has a useful feature where custom methods can be triggered on various events, such as item creation, saving, publishing, deletion, etc. These custom handlers are configured in the webconfig in Sitecore 7, or in App_Config\Sitecore.config in Sitecore 8, like so:
In the example above, a custom handler is being added to the publish:end event, which will trigger when an item has finished publishing. The “type” specifies the class (“Velir.Data.CustomSitecore.Handlers.ItemPublished”), and “method” specifies the method in the class (“RefreshCachedNavigation”).
In my case, I used the “publish:end” event to clear the cache whenever an item was published. My site had an extensive navigation menu that is cached to improve load time, but the caching resulted in changes to the navigation menu not showing up until the app pool was recycled. To resolve this, I attached added a custom handler to “publish:end” so that the cache will be cleared every time a navigation item is published.
I ran into a problem, though. If I was simply clearing the cache on every item publish, the method would be straightforward. However, I only wanted to clear the cache when the navigation menu was altered, and in order to determine that, I needed to check the item that had been published. This was the method I implemented:
This worked just fine for the local publishing event. However, because our production environment uses a CD/CM server configuration, I also needed to add my publishing handler to the “publish:end:remote” event.
This is where the problem occurred. When we tried to publish on the CM environment, we found that the cache wasn’t clearing on the CD environment. Some debugging uncovered the exception that was being thrown:
It turns out that “publish:end” and “publish:end:remote” pass different types of EventArgs; “publish:end” passes SitecoreEventArgs while “publish:end:remote” passes PublishEndRemoteEventArgs. This caused an error to occur in Event.ExtractParameter(eventArgs, 0), which attempts to cast eventArgs as type SitecoreEventArgs.
The question remained of how to retrieve the item in the remote case. SitecoreEventArgs has a parameter of type object named Parameters, which is what Event.ExtractParameter() pulls the item from. PublishEndRemoteEventArgs does not have Parameters. It does, however, have a Guid parameter named RootItemId. Using Sitecore.Data.Database.GetItem() we were then able to get the item that was published, and proceed through the rest of the method
It’s tricky to work out problems with remote pipeline methods when you cannot debug locally (since my local environment is not CD/CM). We worked through it by using a ton of Logging, and were able to figure out what was going on through extensive trial and error of changing the code, publishing items, and then checking the logs to see what errors (if any) were returned.
It is important to note that different sitecore events pass completely different types of EventArgs which cannot be used interchangeably, so a method that works for one handler may not necessarily work for another handler if it pulls information from the EventArgs. Event.ExtractParameter() only works on type SitecoreEventArgs. SitecoreEventArgs includes the parameters Parameters (object), EventName (string), and Result (EventResult); PublishEndRemoteEventArgs includes none of these, but does include RootItemId (Guid). Lesson learned: Always research what type of EventArgs any Sitecore event passes when adding a custom handler to that event.