MEF2 doesn't provide a way to generate exports on the fly, which makes me a sad boi.

The Journey to MEF2

In my ongoing efforts to publish my treasure trove of useful personal code to my Bad Echo Technologies repo so that I may use it for further (more Omnified) projects, I’ve ensured to modernize a number the systems so that they are all based on the newest, greatest technology. One system receiving this treatment right now is my Extensibility framework, which is a plugin framework that used to be powered by MEF1, found in System.ComponentModel.Composition.

For this framework, I decided to upgrade its underlying technology so that it instead would be powered by MEF2 running on .NET 5.0, found in System.Composition. This version of MEF is more modern, and much more performant. With this gain in performance, however, comes a loss in features. My main struggles have been concerned with how to provide the same functionality my framework previously had in light of this loss in features.

I’ve been successful in making up for a number of the removed features, however one particular capability, now missing, has plagued me of late. It is perhaps something whose absence has plagued you, the reader. What I am speaking of is, of course, the complete lack of any equivalent to MEF1’s ComposeExportedValue<T> method.

What Does ComposeExportedValue<T> Do?

The method name is a bit of a mouthful, and it surely means nothing to most people who are unfamiliar with Managed Extensibility Framework parlance. ComposeExportedValue<T> allows you to generate exports on the fly into a compositional container. This allows you to initialize types that require other exported values to be injected into their constructors.

I firmly believe that once an object has been returned by its constructor that it should be, as much as possible, fully initialized and ready for use. Any sort of deviation from this practice, such as objects that require instantiation and then a separate call to an Initialize() style method, inevitably results in brittle code. Therefore, there is great value in allowing for an object that relies on pluggable parts to require those parts be provided in its constructor.

And that’s what ComposeExportedValue<T> gave us the ability to do. Take, as an example, the following exported plugin part:

PluggablePart Class

[Export(typeof(IPluggablePart))]
public class PluggablePart : IPluggablePart
{
    [ImportingConstructor]
    public PluggablePart(IDependency dependency)
    {
        Dependency = dependency;
    }

    public IDependency Dependency { get; }
}

The PluggablePart class requires an IDependency instance in order to function properly (obviously not as it is above — assume this part has methods that make use of that dependency). So, like any properly designed object, it needs to be given all that it requires at the point of initialization, via its constructor. Naturally, this means that the caller, the initializer of the object, needs to provide the dependency at the time of said initialization.

This is clearly not possible, as the only way to receive instances of exported plugin parts through MEF is by use of the ExportProvider.GetExport<T>() family of methods, none of which take any arguments other than an optional contract name or an optional ImportDefinition instance; neither of which provide any sort of means of passing values to an exported parts constructor.

Importing constructors import their arguments, meaning exports for said arguments must’ve already been generated.

And that’s where ComposeExportedValue<T> comes into play. First, please allow me to declare a very simple implementation of IDependency which we will use throughout the article.

ConcreteDependency Class

public class ConcreteDependency : IDependency
{
    public ConcreteDependency(string name)
    {
        Name = name;
    }

    public string Name { get; }
}

Now that I’ve done this, lets go over an example of how ComposeExportedValue<T> is used to provide an instance of the above class to our pluggable part:

Initializing a PluggablePart

var catalog = new DirectoryCatalog(Environment.CurrentDirectory);
var container = new CompositionContainer(catalog);

container.ComposeExportedValue<IDependency>(new ConcreteDependency("Some Behavior-Defining String"));

var part = container.GetExport<IPluggablePart>();

The ComposeExportedValue<T> invocation generates an export for IDependency, providing an initialized ConcreteDependency class implementation as the exported value. If we compared the object returned by the generated part’s IPluggablePart.Dependency property to what we passed in above, we would see they are equivalent, loaded with the string configuration we passed in earlier.

And there we have it. This how we create exported pluggable parts so that the parts, upon being returned, are fully initialized and ready for use. This is the value of ComposeExportedValue<T> and why it is needed.

So How Do We Do This With MEF2?

Dig through System.Composition as much you’d like, but you will find no equivalent for ComposeExportedValue<T> within it. Continue digging through Google search results, and you will find no good solution proposed. Well — unless that’s how you got to this article.

Chest-beating aside, the truth of the matter is: this functionality simply doesn’t exist in MEF2, for a number of reasons that I’ll leave to the authors of the framework to explain. Interestingly enough (and this may be what prompted you to start your search for knowledge), the ImportingConstructorAttribute is included with MEF2.

Don’t importing constructors require you to generate exports on the fly?

Well, no actually. They simply require that the part has been exported. For example, if we had an IDependency implementation declared like so:

AlreadyExportedDependency Class

[Export(typeof(IDependency))]
public class AlreadyExportedDependency : IDependency
{
    public string Name { get; set; }
}

Then, if this export has been processed by the current CompositionHost container, it will be automatically provided to the importing constructor found in our PluggablePart. So, technically, an importing constructor can still be used in MEF2.

All of this however, is really just an exercise in writing useless code.

There’s really nothing gained from these types of declarations. There is no way to actually influence the IDependency.Name property prior to that dependency being provided to the part that requires it. We are essentially back to square one: we have brittle code that requires initialization after instantiation.

The usefulness of ComposeExportedValue<T> is that it allowed us to fully configure a part’s dependencies prior to that part being initialized. Clearly strings are one thing, but in practice our dependencies most likely consist of complex objects. Unfortunately, many developers have been left scratching their heads as to how they can satisfy this important concern with MEF2.

Well, all of this was simply not acceptable to me.

I wanted to port over my Extensibility framework, which has many components that require that there be some sort of way to generate recomposable exports on the fly. Fortunately for me, and hopefully for you, I’ve devised a means to generate recomposable exports on the fly with MEF2.

A Pattern for Generating Exports on the Fly

I’m now going to share with you the pattern I use within my Extensibility framework (found in the BadEcho.Odin.dll general purpose framework library) in order to allow for recomposable, on the fly exports to be able to be generated. If you make use of my code, which is part of the Bad Echo Technologies I’m slowly making available, you don’t need to worry about these details (at least I do not need to worry about them ever again for all my plugin-related work!). But, if you’re just doing your own thing, then you can see how I do it here.

Please be advised that, at the time of writing, I’m still in the process of publishing my code, so if you don’t see the relevant code committed to my repository yet, then that simply means I am still in the process of doing so. Thank you for your patience.

Registering Dependencies

Because MEF2 makes no functionality similar to ComposeExportedValue<T> available, we need our own way of providing initialized dependency values to our exported parts that rely on them. To that end we need to make use of a new class we’ll be defining: the DependencyRegistry<T>.

DependencyRegistry<T> Class

/// <summary>
/// Provides a means to register dependencies ahead of time for injection into pluggable parts
/// during their initialization and exportation.
/// </summary>
/// <typeparam name="T">The type of object depended upon by a pluggable part.</typeparam>
public class DependencyRegistry<T>
{
    /// <summary>
    /// Initializes a new instance of the <see cref="DependencyRegistry{T}"/> class.
    /// </summary>
    public DependencyRegistry()
    {
        Dependency = ArmedDependency;
    }

    /// <summary>
    /// Gets the loaded dependency object for injection into a pluggable part.
    /// </summary>
    public T? Dependency
    { get; }

    /// <summary>
    /// Gets or sets a dependency object armed for injection into a pluggable part.
    /// </summary>
    [field: ThreadStatic]
    internal static T? ArmedDependency 
    { get; set; }
}

A remarkably simple class. We’ll go over how it is used in a moment. I’d put in some validation to ensure a non-null dependency object is being loaded, however it behooves us to leave it simple, so we can use it in the way I’m about to show you; we can simply validate the parameter value like normal within the constructor itself.

Wait a second…what the hell is that?! A static property!!? UNACCEPTABLE!!

Settle down my friends! Yes, I too might be concerned about this, however please be aware that I’d only have a non-private static property on a non-static class if there was no other option. And remember, we’re trying to do something that isn’t exactly built into MEF2. At the end of the article I’ll talk about some of the threading and static aspects of my solution, so please bear with me until then.

Let’s go over how we use this dependency registry first:

Using DependencyRegistry<T>

public void GetExportWithDependencies(CompositionHost container)
{
    var dependency = new ConcreteDependency("Hello there");

    DependencyRegistry<IDependency>.ArmedDependency
        = dependency;

    var part = container.GetExport<IPluggablePart>();
}

Very simple. As you can see, we’re using a CompositionHost, which means we’re in MEF2 land. And, best of all: it works. Even better, we are able to recompose the dependency, meaning we can generate another export with a different dependency value being fed to it.

Recomposable Dependencies!

public void GetExportWithDependencies(CompositionHost container)
{
    var dependency = new ConcreteDependency("Hello there");

    DependencyRegistry<IDependency>.ArmedDependency
        = dependency;

    var part = container.GetExport<IPluggablePart>();

    // This will display: "Hello there"
    Console.WriteLine(part.Dependency.Name);

    var anotherDependency = new ConcreteDependency("This better work...");

    DependencyRegistry<IDependency>.ArmedDependency
        = anotherDependency;

    var anotherPart = container.GetExport<IPluggablePart>();

    // This will display: "This better work..."
    Console.WriteLine(anotherPart.Dependency.Name);
}

Yessss! I’ve managed to achieve this lost bit of functionality in MEF2! But, obviously, simply declaring this new DependencyRegistry<T> class and using it is not enough — we need to take advantage of some other features I’ve made available in my Extensibility framework.

Registering Support With a Convention Provider

In my Odin library’s Extensibility framework I make available a interface known as IConventionProvider, which when exported, causes a number of conventions it provides via a ConventionBuilder to be registered during construction of a CompositionHost by my framework. This interface has been defined while working outside of the scope of this ComposeExportedValue<T> problem, however since I make use of it here, I thought I’d introduce you to it.

IConventionProvider Interface

/// <summary>
/// Defines a provider of rule configurations used to define objects as Odin's Extensibility
/// framework parts.
/// </summary>
public interface IConventionProvider
{
    /// <summary>
    /// Configures the provided convention builder with rules specified by the provider.
    /// </summary>
    /// <param name="conventions">
    /// A convention builder to configure with the provider's rules.
    /// </param>
    void ConfigureRules(ConventionBuilder conventions);
}

By modifying our previously defined PluggablePart class, I can have it provide a convention provider implementation that will wire it up to our dependency registry system. Let’s make some changes to that class now to do this.

PluggablePart Class Hooked up to Dependency Registry System

[Export(typeof(IPluggablePart))]
public class PluggablePart : IPluggablePart
{
    [ImportingConstructor]
    public PluggablePart(IDependency dependency)
    {
        Dependency = dependency;
    }

    public IDependency Dependency { get; }

    [Export(typeof(IConventionProvider))]
    private class LocalDependencyRegistry : DependencyRegistry<IDependency>, IConventionProvider
    {
        public void ConfigureRules(ConventionBuilder conventions)
        {
            conventions.ForType<LocalDependencyRegistry>()
                       .ExportProperties(p => p.Name == nameof(Dependency));
        }
    }
}

And that’s all that is required in order to get the preceding sample usage code to work. To see how my convention providers get registered within my containers, refer to my PluginContextStrategyExtensions class, an extension methods class for IPluginContextStrategy implementations.

Please note that we need to declare a specific private class deriving from DependencyRegistry<T> instead of just creating a convention using .ForType<DependencyRegistry<T>>.

Any PartConventionBuilder instances generated from such a statement will never fire, and if you attempt to use .ForType(typeof(DependencyRegistry<>)), MEF will scold you for trying to export a non-generic contract from an open generic part.

What if IDependency Is Being Exported Somewhere Else?

Ahh, a legitimate concern. If we have an IDependency already being exported by some other part, perhaps by a specific implementation of IDependency, we will run into errors here. To get around this problem, and perhaps create a more resilient exported dependency platform, we can import using part-specific contract names instead.

PluggablePart Using Contract Names

[Export(typeof(IPluggablePart))]
public class PluggablePart : IPluggablePart
{
    private const string DEPENDENCY_CONTRACT = "PluggablePartDependency";

    [ImportingConstructor]
    public PluggablePart([Import(DEPENDENCY_CONTRACT)]IDependency dependency)
    {
        Dependency = dependency;
    }

    public IDependency Dependency { get; }

    [Export(typeof(IConventionProvider))]
    private class LocalDependencyRegistry : DependencyRegistry<IDependency>, IConventionProvider
    {
        public void ConfigureRules(ConventionBuilder conventions)
        {
            conventions.ForType<LocalDependencyRegistry>()
                       .ExportProperties(p => p.Name == nameof(Dependency),
                                         (_, ex) => ex.AsContractName(DEPENDENCY_CONTRACT));
        }
    }
}

This will ensure that only IDependency values exported for use as dependencies for this class get imported into it, and should lessen any collision related fears you might have.

Let’s Neaten Things up a Bit

Well, it might be a bit of a pain to have to type up these conventions every single time we want to configure a dependency for an exported part. Let’s add some life to the fairly simple DependencyRegistry<T> class by making that the convention provider with some stock code. I can’t see the type ever being anything other than a provider of dependency-related conventions, so it makes sense.

Updated DependencyRegistry<T> Class

/// <summary>
/// Provides a means to register dependencies ahead of time for injection into pluggable parts
/// during their initialization and exportation.
/// </summary>
/// <typeparam name="T">The type of object depended upon by a pluggable part.</typeparam>
public abstract class DependencyRegistry<T> : IConventionProvider
{
    private readonly string _contractName;

    /// <summary>
    /// Initializes a new instance of the <see cref="DependencyRegistry{T}"/> class.
    /// </summary>
    /// <param name="contractName">The contract name to export the dependency as.</param>
    protected DependencyRegistry(string contractName)
    {
        _contractName = contractName;

        Dependency = ArmedDependency;
    }

    /// <summary>
    /// Gets the loaded dependency object for injection into a pluggable part.
    /// </summary>
    public T? Dependency
    { get; }

    /// <summary>
    /// Gets or sets a dependency object armed for injection into a pluggable part.
    /// </summary>
    [field: ThreadStatic]
    internal static T? ArmedDependency 
    { get; set; }

    /// <inheritdoc/>
    public void ConfigureRules(ConventionBuilder conventions)
    {
        if (conventions == null)
            throw new ArgumentNullException(nameof(conventions));

        conventions.ForType(GetType())
                   .ExportProperties(p => p.Name == nameof(Dependency),
                                     (_, ex) => ex.AsContractName(_contractName));
    }
}

Very nice. So our pluggable parts with dependencies should only need to look like this from now on:

Final PluggableParts Class

[Export(typeof(IPluggablePart))]
public class PluggablePart : IPluggablePart
{
    [ImportingConstructor]
    public PluggablePart(IDependency dependency)
    {
        Dependency = dependency;
    }

    public IDependency Dependency { get; }

    [Export(typeof(IConventionProvider))]
    private class LocalDependencyRegistry : DependencyRegistry<IFakeDependency>
    {
        public LocalDependencyRegistry()
            : base(DEPENDENCY_CONTRACT)
        { }
    }
}

There you go. Some sweet sexy ComposeExportedValue<T> goodness with fast and sexy MEF2.

Static Properties and Threading Concerns

Before you raise a stink at me for using static fields to accomplish recomposable export creation, let me first state that I believe this approach is actually more thread safe and therefore more stable than what you may have been doing with MEF1. Let’s look again at how we compose exported values in MEF1, and think about everything that can happen between statements:

How Safe Is the MEF1 Approach…

var catalog = new DirectoryCatalog(Environment.CurrentDirectory);
var container = new CompositionContainer(catalog);

container.ComposeExportedValue<IDependency>(new ConcreteDependency("Some Behavior-Defining String"));
// Anything can happen to the container between these two statements
// on a separate thread. As it is, this operation is not atomic.
var part = container.GetExport<IPluggablePart>();

Looks like the original code we may have been porting from isn’t exactly immune to being tampered with by other threads now, is it? Let’s look at our MEF2 exported value composition code again:

And the MEF2 Approach…

public void GetExportWithDependencies(CompositionHost container)
{
    var dependency = new ConcreteDependency("Hello there");

    DependencyRegistry<IDependency>.ArmedDependency
        = dependency;
    // Anything happening on another thread that tampers with
    // DependencyRegistery<IDependency> will actually not affect
    // us at all, since the field is ThreadStatic.
    var part = container.GetExport<IPluggablePart>();
}

Decorating the field with ThreadStatic shields us a bit from the problems one might get when using static memory. But, all of that aside, any and all compositional container operations should only be done as atomically as possible; as in, we should be doing all of this stuff within a locked context.

And, once my framework is fully up there on the GitHub, you’ll see that all compositional arming and exporting is done with lock blocks.

Update: New Armed Approach

While working on fleshing out my Extensibility framework in my source code repository, I changed up both how we made use of the DependencyRegistry<T> type and the type itself. The changes were done to provide thread safety to the armed dependency value without having to lock out other plugin context related actions being executed by my plugin host, including actions arming dependencies of differing types.

Let’s take a look at the changes to DependencyRegistry<T>:

Final DependencyRegistry<T> Class

/// <summary>
/// Provides a means to register dependencies ahead of time for injection into pluggable parts
/// during their initialization and exportation.
/// </summary>
/// <typeparam name="T">The type of object depended upon by a pluggable part.</typeparam>
public abstract class DependencyRegistry<T> : IConventionProvider
{
    private static readonly object _ArmedLock = new();
    private static T? _ArmedDependency;

    private readonly string _contractName;

    /// <summary>
    /// Initializes a new instance of the <see cref="DependencyRegistry{T}"/> class.
    /// </summary>
    /// <param name="contractName">The contract name to export the dependency as.</param>
    protected DependencyRegistry(string contractName)
    {
        _contractName = contractName;

        Dependency = _ArmedDependency;
    }

    /// <summary>
    /// Gets the loaded dependency object for injection into a pluggable part.
    /// </summary>
    public T? Dependency
     { get; }

    /// <summary>
    /// Executes a method that is dependent on the provided dependency value within a context
    /// that guarantees that the provided dependency value is armed throughout the method's
    /// execution.
    /// </summary>
    /// <param name="dependency">
    /// The dependency value to arm for the duration of the method's execution.
    /// </param>
    /// <param name="method">The method to execute within the armed context.</param>
    internal static void ExecuteWhileArmed(T dependency, Action method)
    {
        lock (_ArmedLock)
        {
            _ArmedDependency = dependency;

            method();
        }
    }

    /// <summary>
    /// Executes a method that is dependent on the provided dependency value within a context
    /// that guarantees that the provided dependency value is armed throughout the method's
    /// execution.
    /// </summary>
    /// <typeparam name="TResult">
    /// The type of the value returned by the provided method.
    /// </typeparam>
    /// <param name="dependency">
    /// The dependency value to arm for the duration of the method's execution.
    /// </param>
    /// <param name="method">The method to execute within the armed context.</param>
    /// <returns>The results of executing <c>method</c> within the armed context.</returns>
    internal static TResult ExecuteWhileArmed<TResult>(T dependency, Func<TResult> method)
    {
        lock (_ArmedLock)
        {
            _ArmedDependency = dependency;

            return method();
        }
    }

    /// <inheritdoc/>
    public void ConfigureRules(ConventionBuilder conventions)
    {
        Require.NotNull(conventions, nameof(conventions));

        conventions.ForType(GetType())
                   .ExportProperties(p => p.Name == nameof(Dependency),
                                     (_, ex) => ex.AsContractName(_contractName));
    }
}

I like how this looks much better. We’ve removed the ArmedDependency static property, and instead have methods that take dependency-sensitive delegates which will be executed while guaranteeing the provided dependency value is armed throughout their execution.

Most of the time we will want results back from our dependency-sensitive operation, however sometimes we do not, such as when we are injecting exported parts into loose attributed parts. Therefore, we have two methods here, one for when there is no return result, and the other for when there is.

Given that we now ensure thread safety as far as the value of the armed dependency is concerned, I saw no need to have the armed dependency value remain ThreadStatic, so I ended up removing that.

Here’s an example of some code taking advantage of this new way of doing things in my PluginHost (check out the source code repo for information on all these types):

Using DependencyRegistry<T> in PluginHost

public static IEnumerable<TContract> ArmedLoad<TContract, TDependency>(TDependency value)
{
    Require.NotNull(value, nameof(value));
    PluginContext context = Store.GlobalContext;

    return DependencyRegistry<TDependency>
        .ExecuteWhileArmed(value, context.Load<TContract>);
}

Very nice, and no need to do any locks that’ll block on operations not specifically dealing with injecting dependencies of a particular type. I am very pleased!

Enjoy your newfound ComposeExportedValue<T> functionality within your MEF2 consuming code! Until next time, take care, and thank you for your time!