Dependency Injection in the Managed Extensibility Framework – Simple Injection

This is part one in a series of posts on dependency injection in the Managed Extensibility Framework (MEF). You can find other posts in the series here:

  1. Dependency Injection in the Managed Extensibility Framework – Simple Injection
  2. Dependency Injection in the Managed Extensibility Framework – Optional Injection
  3. Dependency Injection in the Managed Extensibility Framework – Named Contracts

As its default out-the-of-box programming model, the Managed Extensibility Framework (MEF) allows users to apply attributes to types to indicate to MEF dependencies they require and the ‘values’ that they provide. By using the types in the System.ComponentModel.Composition namespace, these dependencies can be automatically determined and satisfied through the use of dependency injection (DI).

As an example, let’s start off with an interface that defines a contract for loading configuration settings:

public interface IConfigurationStore
{
    IDictionary<string, object> LoadSettings();
}

The following type, ConfigurationService, uses the above interface to load a dictionary of configuration settings. its Store property is marked with the [Import] attribute indicating that it requires an instance of IConfigurationStore to work correctly.

public class ConfigurationService
{
    [Import]
    public IConfigurationStore Store
    {
        get;
        set;
    }

    public IDictionary<string, object> Settings
    {
        get;
        private set;
    }

    public void Load()
    {
        Settings = Store.LoadSettings();
    }    
} 

Now let’s say we have another type, RegistryConfigurationStore, which represents a store that loads configuration settings from the registry. It itself is marked with the [Export] attribute, indicating that it provides an implementation of IConfigurationStore.

[Export(typeof(IConfigurationStore))]
public class RegistryConfigurationStore : IConfigurationStore
{
    public IDictionary<string, object> LoadSettings()
    {
        var dictionary = new Dictionary<string, object>();

        // Load from the registry
        [...]

        return dictionary;
    }
}

Okay, so we have two components; one that requires (‘imports’) an IConfigurationStore and one that provides (‘exports’) an IConfigurationStore. The next question is, given that they don’t know about each other, how do we export the IConfigurationStore from RegistryConfigurationStore to satisfy the import on ConfigurationService?

This is where the CompositionContainer fits in. The CompositionContainer provides a way to mesh a set of components together to match the exports on one component to the imports on another.

We start off registering the components in the container:

     CompositionContainer container = new CompositionContainer();

     // Register imports
     ConfigurationService configurationService = new ConfigurationService();
     container.AddComponent(configurationService);

     // Register exports
     container.AddComponent(new RegistryConfigurationStore());

Next, we call CompositionContainer.Bind which, using Reflection, discovers the export on RegistryConfigurationStore, and matches to the import on ConfigurationService.

    // Match exports to imports
    container.Bind();

Once Bind is called, the ConfigurationService is now ready to be used:

 

     // Load the configuration services
     configurationService.Load();

Now, you might be thinking that the matching of the export from RegistryConfigurationStore to the import on ConfigurationService.Store could have been entirely manually without the CompositionContainer, and with a lot less code:

       ConfigurationService configurationService = new ConfigurationService();
       configurationService.Store = new RegistryConfigurationStore();
       configurationService.Load();

Now, this is a fine solution for small non-extensible applications, however, this approach breaks down when building open and dynamic applications. MEF shines when components need to be loaded on demand or when they are not known statically at compile time. In future blog posts, I’ll talk about our MEF provides infrastructure to dynamically discover components and its approach to delaying the creation of a component until absolutely needed.

Published Thursday, June 05, 2008 7:00 AM by David Kean
Filed under:

Comments

Thursday, June 05, 2008 2:58 AM by Steve Degosserie

# re: Dependency Injection in the Managed Extensibility Framework – Simple injection

Hey there,

This first CTP looks good already :)

It gave me some ideas concerning required / optional dependencies between components and dynamic activation/deactivation. Here is a quick & dirty sample :

[Export]

public class ComponentA

{

   [Import]

   public ComponentB B { get; set; }

}

[Export]

public class ComponentB

{

   [Import(IsOptional=true)]

   public ComponentC C { get; set; }

}

[Export]

public class ComponentC

{

}

//-- Begin Test code

ComponentA a = new ComponentA();

ComponentB b = new ComponentB();

ComponentC c = new ComponentC();

CompositionContainer container = new CompositionContainer();

// A is an essentiel component of the system

container.AddComponent<ComponentA>(a /* , ComponentImportance.Essential */);

// B is indirectly essential cause it's a mandatory

container.AddComponent<ComponentB>(b);  dependency of A which is essential

// C is an optional component as it is not a mandatory dependency for any of the registered components

container.AddComponent<ComponentC>(c);

CompositionResult compositionResult = container.TryBind();

if (!compositionResult.Succeeded)

{

   foreach (CompositionIssue issue in compositionResult.Issues)

   {

       Console.WriteLine(String.Format("[{1}] Issue '{0}' : {2}",

           issue.Id, issue.Severity, issue.Description));

   }

   Console.ReadKey();

   return;

}

container.Bind();

Debug.Assert(a.B == b);

Debug.Assert(b.C == c);

/*

// c is an optional dependency of B, can be deactived on the fly

// (ComponentC should publish, through an attribute or interface, its support of "DynamicActivation")

container.DeactivateComponent<ComponentC>(b); // need better syntax (do we need to pass the instance ?) | a more general/flexible invocation of the CompositionContainer's extensible features

Debug.Assert(a.B == b);

Debug.Assert(b.C == null); // or b.C == c but c "non actived/enabled"

container.ActivateComponent<ComponentC>(b);   // same comment as before

Debug.Assert(a.B == b);

Debug.Assert(b.C == c);

container.DeactivateComponent<ComponentB>(b);   // -> Throws exception : cannot deactivate component B as its a mandatory dependency of component A

container.DeactivateComponent<ComponentA>(a);   // -> Throws exception : cannot deactivate component A as its an essential component of the system

*/

container.Dispose();

//-- End Test Code

The ability to dynamically deactivate an optional component in an interconnected components system (e.g. for testing of the integration points between components and their optional dependencies) is a step in the direction of more transparent components.

I'm not sure though wether those concerns are really part of MEF, or any of its possible extensible features ... :)

Also, the ability to modify 'published' properties (settings) of a component at runtime, from a central Component registry would be interesting (same disclaimer as above applies).

Anyway, MEF looks promising :)

 

Thanks for the feedback - this is something we do support out-of-box today in a round about kind of way (via CompositionContainer.RemoveValuesAndBinder) - the exact look of this will change in the next CTP. I'll talk about this in future posts - but we dp support the concept of rebinding - that is, binding a components imports/exports times against what ever happens to be the container.
-David
Thursday, June 05, 2008 4:15 AM by Sidar Ok

# re: Dependency Injection in the Managed Extensibility Framework – Simple injection

I see that you guys are using reflection. I have 2 questions regarding to this :

1 - If you are already using reflection, why is the need for the attributes like [Export]? Doesn't it kill the possibility of injecting dependencies to legacy code ?

2 - Don't you have any performance concerns on using reflection ? Do you have some tests/benchmarks that they will be in a reasonable level ?

This is very Unity style, so my last query is : does MEF mean that Unity is going to be dead ?

1 - I'll answer tomorrow morning.
2 - We haven't hit any performance issues with using Reflection as of yet. However, performance will be a critical factor when running in large applications such as Visual Studio, so it will remain on our radar until we ship.
-David
Wednesday, June 18, 2008 8:05 AM by Sidar Ok

# re: Dependency Injection in the Managed Extensibility Framework – Simple Injection

Hi Dave,

Thanks I'll be monitoring for it. I also put together a post for the ones interested in getting up & goin :

www.sidarok.com/.../managed-extensibility-framework-mef-at-a-glance.html

Wednesday, June 25, 2008 12:20 PM by Alfred Myers

# re: Dependency Injection in the Managed Extensibility Framework – Simple Injection

Have you guys considered a design where the atribute Export was not necessary or optional?

Since the class implementes a given interface, I do not understand the need for specifying the interface again in an Export attribute's property.

I haven't played with the bit, so the question is based solely on the post sample code itself.

We've considered the design, however, we going to stick with the [Export] attribute. The attribute enables a number of scenarios; it allows easy discoverability (for example, we can point a Resolver to a directory containing assemblies, and it will only export objects that are marked with the attribute), and it reduces uncertainty (for example, what happens if the class is importing multiple interfaces, or inherits from a base class, which do you choose?).
However, one thing I should make clear is that today - the attributes are just our default programming model. We are planning on making it very easy to develop your own programming model that does not require attributes. Today in the CTP that would be implemented by inheriting from ComponentBinder and passing that into the container (either via AddBinder or via a ValueResolver). We not quite where we want to be with regards to this, however, our next CTP will be very close.

Friday, April 10, 2009 10:10 PM by Model Yachts

# Model Yachts

2008 (1) August (1) teen model search that will knock your socks off.