Plugins

XML Configuration file has elements to specify plugins. Plugins are extensions that allow specifying additional type bindings, plugin specific settings and some other functionality:

Adding a Plugin

To add a plugin do the following:

  1. Add a child element plugin to iocConfiguration/plugins and specify the plugin name using the name attribute. See the example below:

    Note

    All the types related to plugins should be in assemblies that are in a directory [plugins directoy][plugin name], where [plugins directoy] is the directory specified in attribute pluginsDirPath of element iocConfiguration/plugins and [plugin name] is the value of attribute name of element iocConfiguration/plugins/plugin.

    <plugins pluginsDirPath="K:\...\TestDlls\PluginDlls">
    
        <!--
        Plugin assemblies will be in a folder with similar name under pluginsDirPath folder.
        The plugin folders will be included in assembly resolution mechanism.
        -->
    
        <!--A folder K:\...\TestDlls\PluginDlls\Plugin1 should exist.  -->
        <plugin name="Plugin1" />
        <plugin name="Plugin2" />
        <plugin name="Plugin3" enabled="false" />
    </plugins>
    
  2. Add a child element pluginSetup to iocConfiguration/pluginsSetup (iocConfiguration/pluginsSetup is next to iocConfiguration/startupActions element), and make sure to use the same value for plugin attribute as the value of attribute name in plugin element mentioned in step 1).

  • Here is an example of iocConfiguration/pluginsSetup/pluginSetup element with explanation of some elements in pluginSetup element.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
<pluginsSetup>
    <pluginSetup plugin="Plugin1">
        <!--The type in pluginImplementation should be non-abstract class
                  that implements IoC.Configuration.IPlugin and which has a public constructor-->
        <pluginImplementation type="TestPluginAssembly1.Implementations.Plugin1">
            <parameters>
                <int64 name="param1" value="25" />
            </parameters>
            <injectedProperties>
                <int64 name="Property2" value="35"/>
            </injectedProperties>
        </pluginImplementation>

        <settings>
            <int32 name="Int32Setting1" value="25" />
            <int64 name="Int64Setting1" value="38" />
            <string name="StringSetting1" value="String Value 1" />
        </settings>

        <webApi>
            <controllerAssemblies>
                <!--
                Specify assemblies with API controllers.
                The user of IoC.Configuration should add the assemblies to MVC using
                IMvcBuilder.AddApplicationPart(System.Reflection.Assembly)
                -->
                <controllerAssembly assembly="pluginassm1" />
                <controllerAssembly assembly="plugin1api" />
            </controllerAssemblies>
        </webApi>

        <dependencyInjection>
            <modules>
                <module type="ModulesForPlugin1.Ninject.NinjectModule1">
                    <parameters>
                        <int32 name="param1" value="101" />
                    </parameters>
                </module>
                <module type="ModulesForPlugin1.Autofac.AutofacModule1">
                    <parameters>
                        <int32 name="param1" value="102" />
                    </parameters>
                </module>
                <module type="ModulesForPlugin1.IoC.DiModule1">
                    <parameters>
                        <int32 name="param1" value="103" />
                    </parameters>
                </module>
            </modules>

            <services>
                <service type="TestPluginAssembly1.Interfaces.IDoor">
                    <implementation type="TestPluginAssembly1.Implementations.Door"
                                    scope="transient">
                        <parameters>
                            <int32 name="Color" value="3" />
                            <double name="Height" value="180" />
                        </parameters>
                    </implementation>
                </service>

                <service type="TestPluginAssembly1.Interfaces.IRoom">
                    <implementation type="TestPluginAssembly1.Implementations.Room"
                                    scope="transient">
                        <parameters>
                            <object name="door1" type="TestPluginAssembly1.Interfaces.IDoor"
                                    value="5,185.1" />
                            <injectedObject name="door2" type="TestPluginAssembly1.Interfaces.IDoor" />
                        </parameters>
                        <injectedProperties>
                            <object name="Door2" type="TestPluginAssembly1.Interfaces.IDoor"
                                    value="7,187.3" />
                        </injectedProperties>
                    </implementation>
                </service>
            </services>

            <autoGeneratedServices>
                <!--The scope for autoService implementations is always singleton -->
                <autoService interface="TestPluginAssembly1.Interfaces.IResourceAccessValidatorFactory">
                    <autoMethod name="GetValidators"
                                returnType="System.Collections.Generic.IEnumerable[TestPluginAssembly1.Interfaces.IResourceAccessValidator]"
                                reuseValue="true" >
                        <methodSignature>
                            <string paramName="resourceName"/>
                        </methodSignature>
                        <if parameter1="public_pages">
                            <collection>
                                <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                            </collection>
                        </if>
                        <if parameter1="admin_pages">
                            <collection>
                                <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                                <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator2"/>
                            </collection>
                        </if>
                        <default>
                            <collection>
                                <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator2"/>
                                <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                            </collection>
                        </default>
                    </autoMethod>
                </autoService>
            </autoGeneratedServices>
        </dependencyInjection>
    </pluginSetup>
</pluginsSetup>

Element pluginImplementation

The element iocConfiguration/pluginsSetup/pluginSetup/pluginImplementation is used to specify an implementation of interface IoC.Configuration.IPlugin for the plugin. The easiest way to provide an implementation of IoC.Configuration.IPlugin is to extend the abstract class IoC.Configuration.PluginAbstr and to override the abstract methods IoC.Configuration.PluginAbstr.Initialize() and IoC.Configuration.PluginAbstr.Dispose(). PluginAbstr implements IoC.Configuration.IPlugin.

Note

Plugins are integrated into dependency injection mechanism. Therefore, the constructor parameters of IoC.Configuration.IPlugin implementations specified in pluginImplementation elements will be injected using the bindings specified in XML Configuration file or in modules referenced by the configuration file. Also, parameters and injectedProperties elements can used with pluginImplementation element to specify constructor parameters or property injection.

Here is an example of implementation of IoC.Configuration.IPlugin interface that is referenced in element iocConfiguration/pluginsSetup/pluginSetup/pluginImplementation in example above:

public class Plugin1 : IoC.Configuration.PluginAbstr
{
    private readonly List<SettingInfo> _requiredSettings;

    public Plugin1(long param1)
    {
        Property1 = param1;
        _requiredSettings = new List<SettingInfo>();
        _requiredSettings.Add(new SettingInfo("Int32Setting1", typeof(int)));
        _requiredSettings.Add(new SettingInfo("StringSetting1", typeof(string)));
    }

    public override IEnumerable<SettingInfo> RequiredSettings => _requiredSettings;

    public override void Dispose()
    {
        // Dispose resources
    }

    public override void Initialize()
    {
        // Do initialization here
    }

    public long Property1 { get; }
    public long Property2 { get; set; }
}

Getting Plugin Data at Runtime

  • To access an instance of IoC.Configuration.IPlugin for specific plugin, inject type IoC.Configuration.IPluginDataRepository (using constructor or property injection), and use the method IPluginData GetPluginData(string pluginName) in interface IoC.Configuration.IPluginDataRepository.

An example is demonstrated below:

public class AccessPluginDataExample
{
    public AccessPluginDataExample(IoC.Configuration.IPluginDataRepository pluginDataRepository)
    {
        var pluginData = pluginRepository.GetPluginData("Plugin1");
        Assert.AreEqual(35, pluginData.Property2);
        Assert.AreEqual(25,
            pluginData.Settings.GetSettingValueOrThrow<int>("Int32Setting1"));
    }
}

Element typeDefinition in plugin section

Element iocConfiguration/pluginsSetup/pluginSetup/typeDefinitions/typeDefinition can be used in plugin section to reference types by type alias, the same way this element is used in non-plugin section.

Refer to Using Types in Configuration File for more details on typeDefinition element.

Example of typeDefintion elements in pluginSetup element:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<pluginsSetup>
    <pluginSetup plugin="Plugin1">
        <pluginImplementation type="TestPluginAssembly1.Implementations.Plugin1_Simple" />
        <typeDefinitions>
            <!--Generic1_1_of_Interface1_Impl1 type definition overrides the
                definition in non-plugins section.-->
            <typeDefinition alias="ReadOnlyListOfGenericType"
                            type="System.Collections.Generic.IReadOnlyList" assembly="corlib">
                <genericTypeParameters>
                    <typeDefinition type="SharedServices.Implementations.Generic.Generic3_1" >
                        <genericTypeParameters>
                            <typeDefinition
                                type="SharedServices.Implementations.Interface1_Impl1" />
                        </genericTypeParameters>
                    </typeDefinition>
                </genericTypeParameters>
            </typeDefinition>
            <typeDefinition alias="IDoor" type="TestPluginAssembly1.Interfaces.IDoor" />
            <typeDefinition alias="Door" type="TestPluginAssembly1.Implementations.Door" />
            <typeDefinition alias="plugin1Module" type="ModulesForPlugin1.IoC.DiModule2" />
        </typeDefinitions>
    </pluginSetup>
<pluginsSetup>

Plugin Settings

An element iocConfiguration/pluginsSetup/pluginSetup/settings can be used to specify plugin specific settings. The format of plugin settings is similar to settings in general area (i.e., in element iocConfiguration/settings). For more details on settings in general refer to Settings.

<!--...-->
<pluginSetup plugin="Plugin1">
    <!--...-->
    <settings>
        <int32 name="Int32Setting1" value="25" />
        <int64 name="Int64Setting1" value="38" />
        <string name="StringSetting1" value="String Value 1" />
    </settings>
    <!--...-->
</pluginSetup>

Here is an example of how to access plugin setting values at runtime:

public class AccessPluginDataExample
{
    public AccessPluginDataExample(IoC.Configuration.IPluginDataRepository pluginDataRepository)
    {
        var pluginData = pluginRepository.GetPluginData("Plugin1");

        Assert.AreEqual(25,
                        pluginData.Settings.GetSettingValueOrThrow<int>("Int32Setting1"));
        Assert.AreEqual("String Value 1",
                        pluginData.Settings.GetSettingValueOrThrow<string>("StringSetting1"));
    }
}
  • If a setting is not found in plugin settings element iocConfiguration/pluginsSetup/pluginSetup/settings, IoC.Configuration will search for a setting in general settings area (i.e., in settings defined in element iocConfiguration/settings).
  • To specify required settings, implement the property IEnumerable<SettingInfo> RequiredSettings { get; } in interface IoC.Configuration.IPlugin, or override the virtual property with the same name in IoC.Configuration.PluginAbstr, if the plugin implementation is a subclass of IoC.Configuration.PluginAbstr class.

Plugin Modules

  • Plugin modules can be specified in module elements under element iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/modules.
  • The format of iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/modules is similar to the format of element iocConfiguration/dependencyInjection/modules, except that plugin modules are used to specify type bindings for plugin related types. See Modules for more details on iocConfiguration/dependencyInjection/modules element.

Plugin Type Bindings

Plugin related type binding can be specified either under element iocConfiguration/dependencyInjection/services to provide plugin related implementations for non plugin interfaces, or under element iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/services for cases when both the service and the implementation are plugin specific.

Note

If the plugin is disabled by setting the value of attribute enabled in element iocConfiguration/plugins/plugin for the specific plugin, the type bindings for the given plugin will be ignored.

Example 1: Plugin Specific Implementation for non Plugin Type

Here is an example of binding a non-plugin service SharedServices.Interfaces.IInterface5 to plugin specific type TestPluginAssembly1.Implementations.Interface5_Plugin1Impl.

<iocConfiguration>
    <!--...-->
    </dependencyInjection>
        <!--...-->
        <services>
            <service type="SharedServices.Interfaces.IInterface5" assembly="shared_services">
                <implementation type="SharedServices.Implementations.Interface5_Impl1"
                                assembly="shared_services"
                                scope="singleton" />
                <implementation type="TestPluginAssembly1.Implementations.Interface5_Plugin1Impl"
                                assembly="pluginassm1" scope="singleton" />
                <implementation type="TestPluginAssembly2.Implementations.Interface5_Plugin2Impl"
                                assembly="pluginassm2" scope="transient" />
                <implementation type="TestPluginAssembly3.Implementations.Interface5_Plugin3Impl"
                                assembly="pluginassm3" scope="transient" />
            </service>
            <!--...-->
        </services>
        <!--...-->
    </dependencyInjection>
</iocConfiguration>

Example 2: Plugin Specific Implementation for Plugin Type

Here is an example of binding a plugin service TestPluginAssembly1.Interfaces.IDoor to plugin specific type TestPluginAssembly1.Implementations.Door.

<iocConfiguration>
    <!--...-->
    <pluginsSetup>
        <pluginSetup plugin="Plugin1">
            <!--...-->
            <dependencyInjection>
                <services>
                    <service type="TestPluginAssembly1.Interfaces.IDoor"
                             assembly="pluginassm1">
                        <implementation type="TestPluginAssembly1.Implementations.Door"
                                        assembly="pluginassm1"
                                        scope="transient">
                            <parameters>
                                <int32 name="Color" value="3" />
                                <double name="Height" value="180" />
                            </parameters>
                        </implementation>
                    </service>
                    <!--...-->
                </services>
                <!--...-->
            <dependencyInjection>
        </pluginSetup>
        <!--...-->
    <pluginsSetup>
    <!--...-->
<iocConfiguration>

Plugin types in collection in non-plugin section

Plugin types can be used in value initializer elements for specifying items in collection element plugin as well as in non-plugin section.

Note

Refer to collection element for more details on collection element.

Note

Refer to Value Initialization Elements for more details on value intialization elements.

If value of plugin type is used in a collection item in non-plugin section, and the plugin is disabled by setting the value of attribute enabled in element iocConfiguration/plugins/plugin for the specific plugin, the item will not be included in a collection generated by IoC.Configuration.

Autogenerated Services

An interface with auto-generated implementations can be specified in element iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/autoGeneratedServices. For more information on autogenerated services see Autogenerated Services.

Here is an example of autoGeneratedServices for a plugin. In this example, IoC.Configuration will generate an implementation of TestPluginAssembly1.Interfaces.IResourceAccessValidatorFactory and will configure a type binding, that ,apts the interface IResourceAccessValidatorFactory to auto-generated type.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<autoGeneratedServices>
    <autoService interface="TestPluginAssembly1.Interfaces.IResourceAccessValidatorFactory">
        <autoMethod name="GetValidators"
                    returnType="System.Collections.Generic.IEnumerable[TestPluginAssembly1.Interfaces.IResourceAccessValidator]"
                    reuseValue="true" >
            <methodSignature>
                <string paramName="resourceName"/>
            </methodSignature>

            <if parameter1="public_pages">
                <collection>
                    <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                </collection>
            </if>

            <if parameter1="admin_pages">
                <collection>
                    <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                    <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator2"/>
                </collection>
            </if>

            <default>
                <collection>
                    <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator2"/>
                    <injectedObject type="TestPluginAssembly1.Interfaces.ResourceAccessValidator1"/>
                </collection>
            </default>
        </autoMethod>
    </autoService>
</autoGeneratedServices>

The definition of interface IResourceAccessValidatorFactory is shown below

public interface IResourceAccessValidatorFactory
{
    IEnumerable<IResourceAccessValidator> GetValidators(string resourceName);
}