Ever since we are using StructureMap we are also using this as a cheap replacement for Managed Extensibility Framework (MEF), as it allows us to scan arbitrary assembly paths for additional types to inject.
As we are also dealing with configuration sections where we specify which plugins or types we want to use in a specific environment, we are tasked with creating instances by their name – which is something StructureMap is not able to do out of the box.
However, with the help of an extension method it is very easy to fix this shortcoming. And here is how it goes.
In our example, we have a ConfigurationSection which is configured in our app.config
like this:
<configuration> <configSections> <section name="customConfigurationSection" type="Net.Appclusive.Core.CustomConfigurationSection, Net.Appclusive.Core" allowLocation="true" allowDefinition="Everywhere" /> </configSections> <customConfigurationSection pluginTypeToBeLoaded="Net.Appclusive.Extensions.CustomPluginType" /> </configuration>
The accompanying ConfigurationSection
class looks then like this:
public class CustomConfigurationSection : ConfigurationSection { public const string SECTION_NAME = "customConfigurationSection"; // ReSharper disable InconsistentNaming #pragma warning disable 649 private static int pluginTypeToBeLoaded; #pragma warning restore 649 // ReSharper restore InconsistentNaming [ConfigurationProperty(nameof(pluginTypeToBeLoaded), IsRequired = true)] public string PluginTypeToBeLoaded { get { return (string)this[nameof(pluginTypeToBeLoaded)]; } set { this[nameof(pluginTypeToBeLoaded)] = value; } } }
Injecting this section is a simple For().Use()
statement somewhere in our Registry
setup:
For() .Use(() => (CustomConfigurationSection) ConfigurationManager .GetSection(CustomConfigurationSection.SECTION_NAME)) .Singleton();
In order to make use of the type name referenced by the ConfigurationSection
we can use the Model
property inside our IContainer
where all plugin types are available for inspection. We do this by defining an extension method with the name GetInstance
that accepts a full qualified class name:
public static object GetInstance(this Container container, string typeName) { var type = container.Model.PluginTypes .Select(e => e.PluginType) .FirstOrDefault(e => e.FullName == typeName); return container.GetInstance(type); }
Now accessing this section and generating an instance from it is straightforward:
public class SomeClass { private readonly Net.Appclusive.Extensions.CustomPluginType instance; public SomeClass(CustomConfigurationSection customConfigurationSection) { instance = (Net.Appclusive.Extensions.CustomPluginType) IoC.DefaultContainer .GetInstance(customConfigurationSection.PluginTypeToBeLoaded); } // ... }
This is all it takes and now we are at the end of today’s post.
PS this is my first post created with StackEdit, so be gentle if I did not get it right the first time.