Dependency Injection in the Managed Extensibility Framework – Named Contracts
This is part three in a series of posts on dependency injection in the Managed Extensibility Framework (MEF). You can find other posts in the series here:
- Dependency Injection in the Managed Extensibility Framework – Simple Injection
- Dependency Injection in the Managed Extensibility Framework – Optional Injection
- Dependency Injection in the Managed Extensibility Framework – Named Contracts
In part one, I showed that you can specify a contract (the thing that binds the ‘import’ and ‘export’ together) by passing a type to the constructor of the [Import] and [Export] attributes. Types are not the only way contracts can be specified; they can also be expressed using strings. For example, taking our types from the previous post, we can replace the typeof(IConfigurationStore) contract, with the literal ‘ConfigurationStore’:
public class ConfigurationService
{
[Import("ConfigurationStore")]
public IConfigurationStore Store
{
get;
set;
}
public IDictionary<string, object> Settings
{
get;
private set;
}
public void Load()
{
Settings = Store.LoadSettings();
}
}
[Export("ConfigurationStore")]
public class RegistryConfigurationStore : IConfigurationStore
{
public IDictionary<string, object> LoadSettings()
{
var dictionary = new Dictionary<string, object>();
// Load from the registry
[...]
return dictionary;
}
}
String contracts come in handy when you want to export a value whose type alone isn’t enough to uniquely describe or identify it. Primitives, such as int and string, typically fall under this bucket, however, string contracts can also be used to export any type.
As an example of exporting a string contract, the following shows a class that exports a database connection string under the contract ‘ConnectionString’:
public class ApplicationSettings
{
[Export("ConnectionString")]
public string ConnectionString
{
get { return "Data Source=.;Initial Catalog=Northwind;Integrated Security=True"; }
}
}
One thing you may have noticed, is that the above type exports the value of a property, instead of an entire type as we’ve seen previously. This is perfectly legal. You can also export fields and methods, which I’ll dig into deeper in a future post.
There are also other ways that you can export values other than via the [Export] attribute. For example, the following shows the same connection string being exported by adding it directly to the container:
CompositionContainer container = new CompositionContainer();
// Export the connection string under contract 'ConnectionString'
container.AddValue("ConnectionString", "Data Source=.;Initial Catalog=Northwind;Integrated Security=True");
This is equivalent to the following example which adds the ApplicationSettings class, defined above, as a component:
CompositionContainer container = new CompositionContainer();
container.AddComponent(new ApplicationSettings());
Above, I’ve shown you how to specify contracts using strings, as well as exporting values by adding them to directly to the CompositionContainer. Next time I’ll talk about exporting and importing collections.