Skip to content

Custom Plugins

Plugins form the cornerstone of CoreConnect’s functionality. In addition to the default plugins bundled with CoreConnect, you have the flexibility to create custom plugins, thereby extending CoreConnect’s capabilities within your application. Once defined and enabled, these custom plugins integrate seamlessly with CoreConnect, indistinguishable from the default plugins. They can be defined directly within your Functions or Gateway applications, or within a separate project or assembly and shared by both. Leveraging CoreConnect’s architecture, custom plugins can access all services provided by the CoreConnect framework, including those offered by the default plugins. Therefore, custom plugins serve as the ideal conduit for incorporating any bespoke logic into your application.

The CoreConnectPlugin Abstract Class

The CoreConnectPlugin abstract class is the base class for all CoreConnect plugins. It provides a set of methods and properties that can be overridden by custom plugins to provide custom functionality.

Let’s take a look at the CoreConnectPlugin class and its members:

// RB2 Core Connect

namespace CoreConnect.Plugins;

/// <summary>
/// To implement this, name this with the exact namespace of the *assembly* with Plugin as a class name. For example:
///
/// AssemblyName: CoreConnect.Commerce.CommerceTools
/// class CoreConnect.Commerce.CommerceTools.Plugin: CoreConnectPlugin {}
/// </summary>
public abstract class CoreConnectPlugin
{

    public static void UseCoreConnectCombined(WebApplication app)
    {

    }

    public static void UseCoreConnectGateway(WebApplication app)
    {

    }

    public static void UseCoreConnectFunctions(WebApplication app)
    {

    }

    public virtual IEnumerable<Type> ImpliedPlugins { get { return Array.Empty<Type>(); } }
    /// <summary>
    /// If true, we skip the plugins check
    /// </summary>
    public virtual bool AlwaysLoad { get {  return false; } }
    public virtual string ConfigurationName => Name;
    public abstract string Name { get; }
    public abstract string Description { get; }
    /// <summary>
    /// Validate the configuration; should return true if succesful.
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="configuration"></param>
    /// <returns></returns>
    public abstract bool CheckConfiguration(ILogger logger, IConfiguration configuration);

    /// <summary>
    /// Return the (extra) architectural components of this plugin
    /// </summary>
    /// <returns></returns>
    public virtual Architecture GetArchitecture()
    {
        return new Architecture { Entries = Array.Empty<ArchitectureEntry>(), Links = Array.Empty<ArchitectureLink>() };
    }

    /// <summary>
    /// Register extra graphql extensions
    /// </summary>
    /// <param name="target"></param>
    public virtual void RegisterGraphqlTypes(Action<Type> target) { }
    /// <summary>
    /// Register graphql type extensions
    /// </summary>
    /// <param name="target"></param>
    public virtual void RegisterGraphqlTypeExtensions(Action<Type> target) { }

    /// <summary>
    /// Called to register things on the service provider.
    /// </summary>
    /// <param name="target">Target project</param>
    /// <param name="logger">Output logger</param>
    /// <param name="configuration">Root configuration</param>
    /// <param name="builder">Target services</param>
    public virtual void RegisterCommonServices(ILogger logger, IConfiguration configuration, IServiceCollection builder)
    {
    }
    /// <summary>
    /// Called to register things on the service provider.
    /// </summary>
    /// <param name="target">Target project</param>
    /// <param name="logger">Output logger</param>
    /// <param name="configuration">Root configuration</param>
    /// <param name="builder">Target services</param>
    public virtual void RegisterGatewayServices(ILogger logger, IConfiguration configuration, IServiceCollection builder)
    {
    }
    /// <summary>
    /// Called to register things on the service provider.
    /// </summary>
    /// <param name="target">Target project</param>
    /// <param name="logger">Output logger</param>
    /// <param name="configuration">Root configuration</param>
    /// <param name="builder">Target services</param>
    public virtual void RegisterFunctionServices(ILogger logger, IConfiguration configuration, IServiceCollection builder)
    {
    }

    /// <summary>
    /// Called to register things on the service provider.
    /// </summary>
    /// <param name="target">Target project</param>
    /// <param name="logger">Output logger</param>
    /// <param name="configuration">Root configuration</param>
    /// <param name="builder">Target services</param>
    public virtual void RegisterCommonServices(ILogger logger, ILoggingBuilder loggerBuiler, IConfiguration configuration, IServiceCollection builder)
    {
        RegisterCommonServices(logger, configuration, builder);
    }
    /// <summary>
    /// Called to register things on the service provider.
    /// </summary>
    /// <param name="target">Target project</param>
    /// <param name="logger">Output logger</param>
    /// <param name="configuration">Root configuration</param>
    /// <param name="builder">Target services</param>
    public virtual void RegisterGatewayServices(ILogger logger, ILoggingBuilder loggerBuiler, IConfiguration configuration, IServiceCollection builder)
    {
        RegisterGatewayServices(logger, configuration, builder);
    }
    /// <summary>
    /// Called to register things on the service provider.
    /// </summary>
    /// <param name="target">Target project</param>
    /// <param name="logger">Output logger</param>
    /// <param name="configuration">Root configuration</param>
    /// <param name="builder">Target services</param>
    public virtual void RegisterFunctionServices(ILogger logger, ILoggingBuilder loggerBuiler, IConfiguration configuration, IServiceCollection builder)
    {
        RegisterFunctionServices(logger, configuration, builder);
    }

    /// <summary>
    /// Called to register web plugins for both Functions & Gateway.
    /// </summary>
    /// <param name="target"></param>
    /// <param name="logger"></param>
    /// <param name="app"></param>
    public virtual void RegisterCommonWebServices(ILogger logger, WebApplication app)
    {
    }

    /// <summary>
    /// Called to register web plugins for the Gateway.
    /// </summary>
    /// <param name="target"></param>
    /// <param name="logger"></param>
    /// <param name="app"></param>
    public virtual void RegisterGatewayWebServices(ILogger logger, WebApplication app)
    {
    }

    /// <summary>
    /// Called to register web plugins for the Functions.
    /// </summary>
    /// <param name="target"></param>
    /// <param name="logger"></param>
    /// <param name="app"></param>
    public virtual void RegisterFunctionWebServices(ILogger logger, WebApplication app)
    {
    }

    /// <summary>
    /// Registers all queue types & impls.
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="registration"></param>
    public virtual void RegisterQueues(ILogger logger, IQueueRegistration registration)
    {
    }

    /// <summary>
    /// Callback to register timers
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="registration"></param>
    public virtual void RegisterTimers(ILogger logger, ITimerRegistration registration)
    {

    }
}

Name, Description and ConfigurationName

This properties define how the plugin is displayed in the CoreConnect UI. The Name property is the name of the plugin, the Description property is a brief description of the plugin, and the ConfigurationName property is the root property on your configuration that will be used for this plugin.

For example:

namespace MyProjectNamespace;
public class MyCustomPlugin : CoreConnectPlugin
{
public override string Name => "MyCustomPlugin";
public override string ConfigurationName => "MyCustomPluginSettings";
public override string Description => "Custom plugin for CoreConnect";
public override bool CheckConfiguration(ILogger logger, IConfiguration configuration)
{
// Check if the configuration is valid
return true;
}
}

Here we are defining a custom plugin called MyCustomPlugin with a description of “Custom plugin for CoreConnect” and a configuration root property of MyCustomPluginSettings. Note that we are also overriding the CheckConfiguration method to validate the configuration of this plugin. Since we have not defined any specific configuration yet, we are just returning true for now.

To use this plugin on your application we will first need to install it on your Program.cs:

// RB2 Core Connect
using CoreConnect.Plugins;
var builder = WebApplication.CreateBuilder(args);
...
builder.Services.AddSingleton<CoreConnectPlugin, MyprojectNamespace.MyCustomPlugin>();
...
app.Run();

Note that this is only registering the plugin but it will not be loaded unless you add it to the list of enabled plugins. To do this, you will need to add it to the Plugins property on your configuration and include a MyCustomPluginSettings property with its specific configuration:

{
"Plugins": [..., "MyprojectNamespace.MyCustomPlugin", ...],
"MyCustomPluginSettings": {
...
}
}

Now that we have a plugin registered and enabled, we can start adding custom functionality to it.

Registering Services

There are several methods on the CoreConnectPlugin class that you can override to register services on the Gateway application, the Functions application or both. Being able to decide which services are registered on each application allows you to have a more granular control over the services that are available to your plugin, and also enables you to install the same plugin on both applications while implementing specific logic for each of them.

  • RegisterCommonServices: Overriding this method allows you to install your own services to both Gateway and Functions.
  • RegisterGatewayServices: Overriding this method allows you to install your own services to just the Gateway.
  • RegisterFunctionsServices: Overriding this method allows you to install your own services to just the Functions.
  • RegisterCommonWebServices: Overriding this method allows you to install your own web services to both Gateway and Functions.
  • RegisterGatewayWebServices: Overriding this method allows you to install your own web services to just the Gateway.
  • RegisterFunctionsWebServices: Overriding this method allows you to install your own web services to just the Functions.

Sample usage:

public override void RegisterFunctionServices(ILogger logger, IConfiguration configuration, IServiceCollection builder)
{
builder.Configure<CustomEmailSettings>(configuration.GetSection(ConfigurationName).GetSection("EmailSettings"));
builder.AddScoped<IEmailProvider, CustomEmailService>();
}

You can use this functionality to implement your own services and web services, and also to override the default services provided by CoreConnect. Once installed your services will be available to the rest of the application and all the enabled plugins.

Registering Queues

CoreConnect’s architecture is based on a message queue system. This means that all the communication between the Gateway and the Functions is done through queues.

  • RegisterQueues: Overriding this method allows you to add your own queue/consumer implementation to CoreConnect.

You can see an example of the usage of this method on the Queuing system section.

Adding Architecture Visualization

  • GetArchitecture: Overriding this method allows you to include your plugin in the architecture representation of your project in the EPanel.

Registering Graphql Types

  • RegisterGraphqlTypes: Overriding this method allows you to add your own Graphql types to CoreConnect.

Registering Timers

  • RegisterTimers: Overriding this method allows you to add your own timers to CoreConnect.

For more information on how to use this method, please refer to the Scheduling section.

Custom EPanel plugins

Besides providing custom functionality to the Gateway and Functions applications, your custom plugins can also add custom menus and pages for the EPanel. The only requirement for this is to implement the IEPanelPlugin interface on your plugin class and to make sure your plugin’s project is defined as a web service (Sdk="Microsoft.NET.Sdk.Web").

namespace MyProjectNamespace;
public class MyCustomPlugin : CoreConnectPlugin, IPanelPlugin
{
public static void Main(string[] args)
{
}
...
public List<EPanelMenuItem> GetMenu(IConfiguration configuration)
{
var menu = new List<EPanelMenuItem>();
menu.Add(new EPanelMenuItem()
{
Priority = 9,
Name = "Testing",
Icon = TablerIcons.Test_pipe,
SubMenu = new List<EPanelMenuItem>()
{
new EPanelMenuItem()
{
Priority = 0,
Name = "MyProject's test coverage",
Icon = MDIcons.Chart_bar,
Url = "/tests/MyProjectsCoverage"
}
}
});
return menu;
}
}

In this example, we are adding a new menu item to the EPanel with the name “Testing” and a sub-menu item with the name “MyProject’s test coverage”.