Take the community feedback survey now.

Scott Reed
Nov 9, 2020
  87
(0 votes)

Handling Delete Content Events Within the Waste Basket / Trash

When working with episerver content events expsed to you via the IContentEvents service that involve deleting content we have a couple of events

  • DeletingContent - Which fires when attempting to delete content and allows you to return a boolean to stop it
  • DeletedContent - Which fires after the item has been deleted.

However it's important to be aware when these events fire...

Both of these events actually fire when deleting from trash directly or when clicking the "Empty Trash" button. If you were these to fire when the item is moved to trash / waste basket you'd be wrong and you actually need to handle the MovedContent / MovingContent events.

Now when it comes to working with these two deletion events it's important to know that there's an odd kink in how these work depending on if you've selected Delete on an item in trash or you've clicked the "Empty Trash" button.

The key difference is

  1. When handling the event from a direct delete on a specific item in the trash / waste basket, the passed item to the event handler is the ContentLink of the item
  2. When handing the event from the "Empty Trash" button, the passed item to the event handler in the ContentLink of the WasteBasket. It's also worth noting that getting the children of the waste basket DID NOT work and I had to use descendants.

So as a code example in a recent project I had to hook in to this event to delete an item from a custom database table sorting some related information and this lead to me implementing the following (excuse the use of DataFactory / No Dependency Inject it's due to the project it's used on).

// <summary>
    /// Handles content events from Episerver
    /// </summary>
    /// <seealso cref=IInitializableModule" />
    [InitializableModule]
    [ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
    public class ContentEventsInitialization : IInitializableModule
    {
        /// <summary>
        /// Initializes this instance.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <remarks>
        /// Gets called as part of the EPiServer Framework initialization sequence. Note that it will be called
        /// only once per AppDomain, unless the method throws an exception. If an exception is thrown, the initialization
        /// method will be called repeadetly for each request reaching the site until the method succeeds.
        /// </remarks>
        public void Initialize(InitializationEngine context)
        {
            var events = ServiceLocator.Current.GetInstance<IContentEvents>();
            events.DeletingContent += DeletingContent;
        }

        /// <summary>
        /// Preloads the specified parameters.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        public void Preload(string[] parameters)
        {
        }

        /// <summary>
        /// Resets the module into an uninitialized state.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <remarks>
        /// <para>
        /// This method is usually not called when running under a web application since the web app may be shut down very
        /// abruptly, but your module should still implement it properly since it will make integration and unit testing
        /// much simpler.
        /// </para>
        /// <para>
        /// Any work done by <see cref="M:EPiServer.Framework.IInitializableModule.Initialize(EPiServer.Framework.Initialization.InitializationEngine)" /> as well as any code executing on <see cref="E:EPiServer.Framework.Initialization.InitializationEngine.InitComplete" /> should be reversed.
        /// </para>
        /// </remarks>
        public void Uninitialize(InitializationEngine context)
        {
        }

        /// <summary>
        /// Deletings the content.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="ContentEventArgs"/> instance containing the event data.</param>
        private void DeletingContent(object sender, ContentEventArgs e)
        {
            RemoveAlertsFromDatabase(e);
        }

        /// <summary>
        /// Handles removing of alerts from database when they are deleted.
        /// </summary>
        /// <param name="e">The <see cref="ContentEventArgs"/> instance containing the event data.</param>
        private void RemoveAlertsFromDatabase(ContentEventArgs e)
        {
            var alertsManager = new AlertsManager();

            if (e.ContentLink.ID == ContentReference.WasteBasket.ID)
            {
                var wasteBasketReferences = DataFactory.Instance.GetDescendents(e.ContentLink);

                foreach (var wasteBasketReference in wasteBasketReferences)
                {
                    var item = DataFactory.Instance.Get<IContent>(wasteBasketReference);

                    if (item is AlertItem)
                    {
                        alertsManager.RemoveAlerts(wasteBasketReference.ID);
                    }
                }
            }

            if (e.Content is AlertItem)
            {
                alertsManager.RemoveAlerts(e.ContentLink.ID);
            }
        }
    }

Hopefully this helps anyone with working with delete events when in the trash

Nov 09, 2020

Comments

Please login to comment.
Latest blogs
A day in the life of an Optimizely OMVP - Opticon London 2025

This installment of a day in the life of an Optimizely OMVP gives an in-depth coverage of my trip down to London to attend Opticon London 2025 held...

Graham Carr | Oct 2, 2025

Optimizely Web Experimentation Using Real-Time Segments: A Step-by-Step Guide

  Introduction Personalization has become de facto standard for any digital channel to improve the user's engagement KPI’s.  Personalization uses...

Ratish | Oct 1, 2025 |

Trigger DXP Warmup Locally to Catch Bugs & Performance Issues Early

Here’s our documentation on warmup in DXP : 🔗 https://docs.developers.optimizely.com/digital-experience-platform/docs/warming-up-sites What I didn...

dada | Sep 29, 2025

Creating Opal Tools for Stott Robots Handler

This summer, the Netcel Development team and I took part in Optimizely’s Opal Hackathon. The challenge from Optimizely was to extend Opal’s abiliti...

Mark Stott | Sep 28, 2025

Integrating Commerce Search v3 (Vertex AI) with Optimizely Configured Commerce

Introduction This blog provides a technical guide for integrating Commerce Search v3, which leverages Google Cloud's Vertex AI Search, into an...

Vaibhav | Sep 27, 2025

A day in the life of an Optimizely MVP - Opti Graph Extensions add-on v1.0.0 released

I am pleased to announce that the official v1.0.0 of the Opti Graph Extensions add-on has now been released and is generally available. Refer to my...

Graham Carr | Sep 25, 2025