Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7972993
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 4, 20262026-06-04T07:59:33+00:00 2026-06-04T07:59:33+00:00

Hi i have a database application which uses registered modules. Modules are registered via

  • 0

Hi i have a database application which uses registered modules.

Modules are registered via MEF, I need to provide settings to these modules (whose settings are also stored in the database).

Each plugin will implement different interfaces (that do different things through different interfaces).

As of now, i currently have a separate plugin container for each interface type – whilst the below works, there is a lot of replication for each and every plugin type.

The modules and module setting table is in a sql database with the following field types

[Table_PluginModules]
PluginId => Guid, PK
Enabled => boolean

[Table_PluginModule_settings]
PluginId => Guid, PK(col1), FK(Table_PluginModules.PluginID)
SettingName => varchar, PK(col2)
SettingValue => varchar

The module interfaces are below

interface ICar
{
    string Name;
    Guid PluginID;
    void Handbrake();
}

interface IBike
{
    string Name;
    Guid PluginID;
    void Peddle();
}

Then i have the plugin managers for the ICar and IBike interfaces

class CarPluginsManager()
{
  [ImportMany] 
  public ICar[] Plugins 

  void LoadPluginsCar()
  {
    var cat = new DirectoryCatalog(path, "*.dll"); 
    var container = new CompositionContainer(cat); 
    container.ComposeParts(this); 
    foreach (ICar plugin in Plugins) 
    { 
        // load settings from database for this plugin
        List<ModuleSetting> settings = ModelContext.PluginSettings( x => x.PluginId == plugin.Plugin).ToList(); 
        foreach(ModuleSetting setting in settings)
        {
            // do something with the setting value that was retreived for this plugin
            string settingName = setting.SettingName;
            string settingValue = setting.SettingValue;
        }
                // check if previously registered modules are not in the above list and disable if necesasry in the database
    } 
  }

  ICar GetCarPlugin(Guid id)
  {
    foreach (var plugin in Plugins) 
    { 
        if(plugin.PluginID == id)
                {
                          // check module is enabled in the modules database table, if so
            return plugin;
                          // if module is disabled, return null...
                }
    } 
    return null;
  }

}

class BikePluginsManager()
{
  [ImportMany] 
  public IBike[] Plugins 

  void LoadPluginsCar()
  {
    var cat = new DirectoryCatalog(path, "*.dll"); 
    var container = new CompositionContainer(cat); 
    container.ComposeParts(this); 
    foreach (ICar plugin in Plugins) 
    { 
        // load settings from database for this plugin
        List<ModuleSetting> settings = ModelContext.PluginSettings( x => x.PluginId == plugin.Plugin).ToList(); 
        foreach(ModuleSetting setting in settings)
        {
            // do something with the setting value that was retreived for this plugin
            string settingName = setting.SettingName;
            string settingValue = setting.SettingValue;
        }
                // check if previously registered modules are not in the above list and disable if necesasry in the database
    }  
  }

  IBike GetBikePlugin(Guid id)
  {
    foreach (var plugin in Plugins) 
    { 
        if(plugin.PluginID == id)

                          // check module is enabled in the modules database table, if so
            return plugin;
                          // if module is disabled, return null...
    } 
    return null;
  }
}

Other aspects of the business logic code will reference different modules to do different things.

When modules are loaded, i check if any previously registered modules are missing (in case DLLs were removed from the plugin directory) and disable the plugin in the plugin table.

These modules need to be ‘registered’ in the database so we can reference these modules as foreign keys (users can select different output modules), I am currently doing this through a table called plugins (defined at the top of this post) and an example actions table below:

[Table_Some_Action]
ActionID => int, PK
ModuleID => Guid, FK(Table_Modules)

So, I would like to make this common/generic, however i still need to be able to reference interfaces by interface type. What i am thinking of is doing something along the lines of:

interface IPlugin
{
    string Name;
    Guid PluginID;
}

IPlugInterfaceCar : IPlugin
{
void ApplyHandbrake();
}

IPlugInterfaceBike : IPlugin
{
void Peddle();
}

class CarPluginBinary : IPlugInterfaceCar
{
    void ApplyHandbrake() {}
}

class BikePluginBinary : IPlugInterfaceBike
{
    void ApplyHandbrake() {}
}

The problem is how do i handle the different types when the plugin manager class that composes the parts expects a single interface (or infact, we wont know these interfaces in advance, as they are loaded at runtime).

Any direction on this design strategy, including this reference to the modules from a database, would be very much appreciated.

Thanks,

Chris

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-04T07:59:34+00:00Added an answer on June 4, 2026 at 7:59 am

    I have written the following modules and linked the plugin module as an attribute. Unfortunatly it is a string as i dont think its possible to have GUID literals, however it does the job.

    I think it is more flexible than the code before without having to resort to a single base interface type, and I can now link to the modules in the database via an FK, whenever the code willinstantiate a module the ID and interface are checked to ensure they are both valid.

    Comments appreciated if you spot any other problems or improvements.

    Plugin manager

    public interface IPluginManagerService
    {
        void RegisterModules();
        IExternalAccountsPlugin GetExternalAccountsPlugin(Guid id);
        IRecoveryActionPlugin GetExternalRecoveryActionsPlugin(Guid id);
    }
    
    namespace MyNamespace.Services
    {
        public class PluginManagerService : ServiceBase, IPluginManagerService
        {
            public PluginManagerService(ILogger logger, IUnitOfWork unitOfWork)
                : base(logger)
            {
                m_UnitOfWork = unitOfWork;
                RegisterModules();
            }
    
            protected IUnitOfWork m_UnitOfWork;
            object Lock = new object();
    
            // do not make public so we can perform further checks via strongly typed accessor functions
            // get a list of modules that implement contracts of type T
            protected IEnumerable< Lazy<T, IPluginMetadata> > GetInterfaces<T>()
            {
               return m_Container.GetExports<T, IPluginMetadata>();
            }
    
            // do not make public so we can perform further checks via strongly typed accessor functions
            // returns the plugin with the provided ID
            protected T GetPlugin<T>(Guid id)
            {
                return m_Container.GetExports<T, IPluginMetadata>().Where(x => x.Metadata.PluginID == id.ToString().ToUpper()).Select(x => x.Value).FirstOrDefault();
            }
    
            public IExternalAccountsPlugin GetExternalAccountsPlugin(Guid id)
            {
                return GetPluginModule<IExternalAccountsPlugin>(id);
            }
    
            public IRecoveryActionPlugin GetExternalRecoveryActionsPlugin(Guid id)
            {
                return GetPluginModule<IRecoveryActionPlugin>(id);
            }
    
            /* return a list of all available externalAccounts plugins */
            public IEnumerable<Guid> ListExternalAccountsPluginIDs()
            {
                List<Guid> guids = new List<Guid>();
    
                foreach (string id in GetInterfaces<IExternalAccountsPlugin>().Select(x => x.Metadata.PluginID).ToList())
                {
                   guids.Add(Guid.Parse(id));
                }
                return guids;
            }
    
            protected T GetPluginModule<T>(Guid id)
            {
                ExternalPlugin pluginInDb = m_UnitOfWork.ExternalPlugins.GetByID(id);
                if (pluginInDb != null)
                {
                    if (pluginInDb.Enabled == true)
                    {
                        T binaryPlugin = GetPlugin<T>(id);
                        if (binaryPlugin == null)
                            throw new KeyNotFoundException();
                        else
                            return binaryPlugin;
                    }
                }
                return default(T);
            }
    
            CompositionContainer m_Container;
    
            public void RegisterModules()
            {
                lock (Lock)
                {
                    var pluginContainer = new AggregateCatalog();
                    var directoryPath = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location) + "\\Plugins\\";
                    var directoryCatalog = new DirectoryCatalog(directoryPath, "*.dll");
                    //pluginContainer.Dispose();
                    // directoryCatalog.Refresh();
    
                    LogMessage("Searching for modules in " + directoryCatalog + "...");
    
                    pluginContainer.Catalogs.Add(directoryCatalog);
                    m_Container = new CompositionContainer(pluginContainer);
    
                   // m_Container.ComposeParts(this); // not required, this will load dependencies dynamically onto our object
                    LinkModulesWithDatabase();
                }
            }
    
            string FormatModuleMessage(string name, Guid id, Version version )
            {
                return name + ". ID: " + id + ". Version: " + version.ToString();
            }
    
            protected delegate string ModuleNameHelper<T>(T t);
            protected delegate Version ModuleVersionHelper<T>(T t);
    
            protected void SetVersionOfExternalPlugin(ref ExternalPlugin plugin, int major, int minor, int build, int revision)
            {
                plugin.MajorVersion = major;
                plugin.MinorVersion = minor;
                plugin.Build = build;
                plugin.RevsionVersion = revision;
            }
    
            protected void LoadNewAndExisting<T>(IEnumerable<Lazy<T,IPluginMetadata>> foundModules, ref int added, ref int disabled, ref int upgraded, ref int existing, ModuleNameHelper<T> moduleNameHelper, ModuleVersionHelper<T> moduleVersionHelper)
            {
                List<Guid> foundModuleIDs = new List<Guid>();
    
                foreach (Lazy<T,IPluginMetadata> moduleInAssembly in foundModules)
                {
                    Guid moduleInAssemblyId = Guid.Parse(moduleInAssembly.Metadata.PluginID);
                    Version moduleInAssemblyVersion = moduleVersionHelper(moduleInAssembly.Value);
                    string moduleInAssemblyName = moduleNameHelper(moduleInAssembly.Value);
    
                    ExternalPlugin moduleInDb = m_UnitOfWork.ExternalPlugins.GetByID(moduleInAssemblyId); // see if we can find the registered module in the database
    
                    if (moduleInDb != null)
                    {
                        Version moduleInDbVersion = new Version(moduleInDb.MajorVersion, moduleInDb.MinorVersion,  moduleInDb.Build, moduleInDb.RevsionVersion);
    
                        if (moduleInAssemblyVersion > moduleInDbVersion)
                        {
                            LogMessage("Found updated module (previous version " + moduleInDbVersion + "). Upgrading " + FormatModuleMessage(moduleInAssemblyName, moduleInAssemblyId, moduleInAssemblyVersion));
                            moduleInDb.Enabled = true;
                            SetVersionOfExternalPlugin(ref moduleInDb, moduleInAssemblyVersion.Major, moduleInAssemblyVersion.Minor, moduleInAssemblyVersion.Build, moduleInAssemblyVersion.Revision);
                            upgraded++;
                        }
                        else if (moduleInAssemblyVersion < moduleInDbVersion)
                        {
                            LogMessage("Found old module (expected version " + moduleInDbVersion +"). Disabling " + FormatModuleMessage(moduleInAssemblyName, moduleInAssemblyId, moduleInAssemblyVersion));
                            moduleInDb.Enabled = false;
                            disabled++;
                        }
                        else
                        {
                            LogMessage("Loaded existing module " + FormatModuleMessage(moduleInAssemblyName, moduleInAssemblyId, moduleInAssemblyVersion));
                            moduleInDb.Enabled = true;
                            existing++;
                        }
                        moduleInDb.UpdatedDateUTC = DateTime.Now;
                        m_UnitOfWork.ExternalPlugins.Update(moduleInDb);
                    }
                    else  // could not find any module with the provided ID
                    {
                        ExternalPlugin newModule = new ExternalPlugin();
                        SetVersionOfExternalPlugin(ref newModule, moduleInAssemblyVersion.Major, moduleInAssemblyVersion.Minor, moduleInAssemblyVersion.Build, moduleInAssemblyVersion.Revision);
                        newModule.Enabled = true;
                        newModule.ExternalPluginID = moduleInAssemblyId;
                        newModule.UpdatedDateUTC = DateTime.UtcNow;
                        m_UnitOfWork.ExternalPlugins.Insert(newModule);
                        LogMessage("Loaded new module " + FormatModuleMessage(moduleInAssemblyName, moduleInAssemblyId, moduleInAssemblyVersion));
                        added++;
                    }
                    foundModuleIDs.Add(moduleInAssemblyId);
                }
    
                IEnumerable<Guid> missingModules = m_UnitOfWork.ExternalPlugins.Context.Select(x => x.ExternalPluginID).Except(foundModuleIDs).ToList();
                foreach(Guid missingID in missingModules)
                {
                    ExternalPlugin pluginToDisable = m_UnitOfWork.ExternalPlugins.GetByID(missingID);
                    LogMessage("Cannot find previously registered module in plugin directory. Disabling: " + FormatModuleMessage("Unknown", pluginToDisable.ExternalPluginID, new Version(pluginToDisable.MajorVersion, pluginToDisable.MinorVersion, pluginToDisable.RevsionVersion, pluginToDisable.Build)));
                    pluginToDisable.Enabled = false;
                    pluginToDisable.UpdatedDateUTC = DateTime.UtcNow;
                    m_UnitOfWork.ExternalPlugins.Update(pluginToDisable);
                    disabled++;
                }
    
                m_UnitOfWork.Save();
            }
    
            protected void LinkModulesWithDatabase()
            {
                int added = 0;
                int existing = 0;
                int upgraded = 0;
                int disabled = 0;
    
                LogMessage("Loading ExternalAccountsModule plugins (IExternalAccountsModule).");
                ModuleNameHelper<IExternalAccountsPlugin> accountsModuleNameHelper = delegate (IExternalAccountsPlugin t) { return t.Name; }; 
                ModuleVersionHelper<IExternalAccountsPlugin> accountsModuleVersionHelper = delegate (IExternalAccountsPlugin t) { return t.ModuleVersion; };
                IEnumerable<Lazy<IExternalAccountsPlugin, IPluginMetadata>> accountsPlugins = GetInterfaces<IExternalAccountsPlugin>();
                LoadNewAndExisting<IExternalAccountsPlugin>(accountsPlugins, ref added, ref disabled, ref upgraded, ref existing, accountsModuleNameHelper, accountsModuleVersionHelper);
    
                LogMessage("Finished loading modules, total " + (added + existing + upgraded) + " modules enabled. New: " + added + " . Existing: " + existing + ". Upgraded: " + upgraded + ". Disabled: " + disabled + ".");
            }
        }
    }
    

    Export attribute

    public interface IPluginMetadata
    {
        string PluginID { get; }
    }
    
    [MetadataAttribute]
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class PluginExportAttribute : ExportAttribute, IPluginMetadata
    {
        public PluginExportAttribute(Type t, string guid)
            : base(t)
        {
            PluginID = guid.ToUpper();
        }
    
        public string PluginID { get; set; }
    }
    

    Marking module as a plugin, place this compiled DLL in the plugin directory

    [PluginExport(typeof(IExternalAccountsPlugin),"BE112EA1-1AA1-4B92-934A-9EA8B90D622C")]
    public class MyModule: IExternalAccountsPlugin
    {
    }
    
    IPluginManagerService externalAccountsModuleService = instance.Resolve<IPluginManagerService>();
    IExternalAccountsPlugin accountsPlugin = externalAccountsModuleService.GetExternalAccountsPlugin(Guid.Parse("BE112EA1-1AA1-4B92-934A-9EA8B90D622C"));
    IEnumerable<Guid> pluginIDs = externalAccountsModuleService.ListExternalAccountsPluginIDs();
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have an application which uses Hibernate for database transactions, I have mapped all
I have a Spring application which uses Hibernate on a PostgreSQL database. I'm trying
I have an application which uses a SQL database. This is encapsulated by a
I have a WinForm application which uses SqlServer CE 3.5 as database. I use
I currently have an application which uses EF database first which was built against
I have created a windows form application which uses an SQL database. The database
I have an application which uses traditional Database for all of its data ,
I have winforms application which uses nhibernate and active records to access the database.
I have created a application which uses Sqlite database. Now i wanted to deploy
I have a PHP web application which uses a MySQL database for object tagging,

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.