Article Executing Code Before Plugin Initialization

The IBeforeInitializationPlugin is a plugin that allows you to execute code after plugins are instantiated but before plugins initialize. 

What would I use IBeforeInitializationPlugin for?

This plugin is useful anytime you have something that needs to be available to all your custom plugins before they initialize.  This could be something as simple as a global variable.  More commonly it is useful if you are using a Dependency Injection framework(referred to later as a DI Framework) and you must bind your services.   

 Required Platform DLL References:

  • Telligent.Evolution.Platform.dll

Plugin Lifecycle

If you are not already you should familiarize yourself with the Plugin Lifecycle.  IBeforeInitializationPlugins will execute after enabled plugins are instantiated and configured and before Apis are registered.  This means any global variables (assuming static variables assigned a value or variables in the proper scope) or bound services from for your DI framework will be available in an IApiDefinition plugin if you are using one or if not in a plugin's Initialize() method and later.  These would not be available for use when IRecurringEvolutionJobs register their default schedules or context, IConfigurablePlugins define configuration, or ITranslatablePlugins register their translations.   Platform In-Process Apis are also not available during the before initialization process.

Creating an IBeforeInitializationPlugin

An IBeforeInitializationPlugin in addition to the normal IPlugin members only have a single method, BeforeInitialization receiving a BeforeInitializationArguments object.   This plugin is slightly different than most others in the sense that is written like its an Event handler, though it is not a true event.  Instead the BeforeInitialization(...) is a normal method invoked by the platform before plugin initialization. 

public interface IBeforeInitializationPlugin:IPlugin
{
    void BeforeInitialize(BeforeInitializationArguments args);
}

The BeforeInitializationArguments exposes an enumeration called PluginInitializationReason that allows you to determine why plugins are being re-initialized.  Currently there are 2 reasons plugins will re-initialize:

  • PluginInitializationReason.AppStart -  Happens when plugins initialize because the application itself is starting or re-starting.
  • PluginInitializationReason.PluginReload - Happens whenever a plugin or plugins are saved and/or enabled or disabled.   This is not just your plugin, it is any plugin currently installed in your community.

 

Service Binding Example

First, this is not meant to be a source on how to use a dependency injection framework nor are we going to illustrate using any specific one.   For this example we will simply show a flow that is common for many using a simulated container.   You should consult your specific framework's documentation on usage and to evaluate its appropriateness for use in this particular implementation.

First create your plugin and have it implement IBeforeInitializationPlugin.  You will notice the standard IPlugin members(omitted below for brevity) and the additional BeforeInitialization(...) member specific to this plugin.  Its here that we will add our service binding logic. 

public class BeforeInitializationPlugin : IBeforeInitializationPlugin
{
    #region IPlugin Members
     
    public void BeforeInitialize(BeforeInitializationArguments args){ }
     
}

In our example the "Container" class is a simulated DI framework collection of service bindings. Consult your frameworks documentation for its specific way of doing service bindings. 

In the sample we want to evaluate 2 conditions when deciding to bind our services.  The most important thing to remember this will only ever run when you enable the plugin so you can be assured if this executes, your plugin is enabled.   You will want to run this when the application starts OR if the container is not bound or initialized.   You need to check that it's initialized because at some point your plugin will be manually enabled and you will want to bind your services immediately, not wait for the next reload or application start.   Again checking if a container in a specific framework can vary by framework so refer to the documentation.   Our sample has an IsInitialized member.

public void BeforeInitialize(BeforeInitializationArguments args)
{
     //This runs before any plugin intializes
     if (args.Reason == PluginInitializationReason.AppStart || !Container.IsInitialized)
     {
         Container.Register<ISampleService>(new SomeSampleService());
     }
}

Depending on your code or framework, it may suffice to only check for the container being initialized or bound since realistically on application start it will not be.  But the option to determine application start specifically is available and is shown here for example purposes if you should need to use it.  The actual line of code in the sample doing the binding is not relevant to the overall purpose of the example as its syntax will vary by framework.

You can test that it all works and that your services are available in the initialization method of the plugin by attempting to retrieve a service from your container.   This example uses our sample DI framework to get a service and invoke a member and outputting the value to the event log. 

public void Initialize()
{
    var service = Container.Get<ISampleService>(); //My service will be available
    Apis.Get<IEventLog>().Write(service.SayHello(), new EventLogEntryWriteOptions());
}

Considerations

If you are writing a simple plugin that needs to utilize before initialization functionality, you can simply extend your existing plugin with IBeforeInitializationPlugin.   If you have multiple plugins that all depend on before initialization logic it is recommended  to use a plugin group with either an implementation of IBeforeInitializationPlugin included in the group, or the plugin group could implement IBeforeInitializationPlugin itself.

 

Source

This is  the full source of the example used in this article.  You can add it to a project, compile it and deploy it to your Verint Community.   After enabling the "BeforeInitializationPlugin Sample" plugin under the Extensions menu in Administration, you should see "Hello" in the event log under the monitoring menu.  It will re-appear if you recycle the application. 

using System;
using System.Collections.Generic;
using Telligent.Evolution.Extensibility;
using Telligent.Evolution.Extensibility.Api.Version1;
using Telligent.Evolution.Extensibility.Version1;

namespace Samples
{
    public class BeforeInitializationPlugin : IBeforeInitializationPlugin
    {
        #region IPlugin Members
        public string Description
        {
            get { return "Executes before plugin initialize"; }
        }

        public string Name
        {
            get { return "BeforeInitializationPlugin Sample"; }
        }
        public void Initialize()
        {
            var service = Container.Get<ISampleService>(); //My service will be available
            Apis.Get<IEventLog>().Write(service.SayHello(), new EventLogEntryWriteOptions());
        }

        #endregion
        public void BeforeInitialize(BeforeInitializationArguments args)
        {
            //This runs before any plugin intializes

            if (args.Reason == PluginInitializationReason.AppStart || !Container.IsInitialized)
            {
                Container.Register<ISampleService>(new SomeSampleService());
            }
        }

     
    }

    #region Container and Service For Sample Purposes
    public static class Container
    {
        private static IDictionary<Type, object> _services = null;

        public static void Register<T>(T instance)
        {
            _services = new Dictionary<Type, object>();
            if (!_services.ContainsKey(typeof(T)))
                _services.Add(typeof(T),instance);
        }

        public static T Get<T>()
        {
            object item;
            _services.TryGetValue(typeof(T), out item);

            if (item == null)
                throw new InvalidOperationException("No binding for specified service was found");

            return (T) item;
        }

        public static bool IsInitialized
        {
            get { return _services != null; }
        }

    }


    public class SomeSampleService:ISampleService
    {
        public string SayHello()
        {
            return "Hello";
        }
    }

    public interface ISampleService
    {
        string SayHello();
    }
    #endregion
}