Hi,
In my old post I explained a way for implementing plug-in with reflection and IO file operations, and Indeed this is one way for doing it. Currently there are frameworks that can simplify this kind of tasks, and these frameworks are more flexible. Here there are two of frameworks:
Microsoft Extensibility Framework (@ http://mef.codeplex.com/Wikipage)
From codeplex site:
“MEF presents a simple solution for the runtime extensibility problem. Until now, any application that wanted to support a plugin model needed to create its own infrastructure from scratch. Those plugins would often be application-specific and could not be reused across multiple implementations.
- MEF provides a standard way for the host application to expose itself and consume external extensions. Extensions, by their nature, can be reused amongst different applications. However, an extension could still be implemented in a way that is application-specific. Extensions themselves can depend on one another and MEF will make sure they are wired together in the correct order (another thing you won’t have to worry about).
- MEF offers a set of discovery approaches for your application to locate and load available extensions.
- MEF allows tagging extensions with additonal metadata which facilitates rich querying and filtering”
Unity (@ http://unity.codeplex.com/)
From codeplex:
“The Unity Application Block (Unity) is a lightweight extensible dependency injection container with support for constructor, property, and method call injection.
Unity addresses the issues faced by developers engaged in component-based software engineering. Modern business applications consist of custom business objects and components that perform specific or generic tasks within the application, in addition to components that individually address cross cutting concerns such as logging, authentication, authorization, caching, and exception handling.
The key to successfully building such applications is to achieve a decoupled or very loosely coupled design. Loosely coupled applications are more flexible and easier to maintain. They are also easier to test during development. You can mock up shims (lightweight mock implementations) of objects that have strong concrete dependencies; such as database connections, network connections, ERP connections, and rich user interface components. ”
So, are they the same framework?
Although both frameworks struggle to allow a better application extensibility, their attack the problem from different fronts. And of course, each framework has their own set of concepts.
Let prepare a quick plug-in with unity
Before continuing, I’d like to clarify that this is only one approach for using unit, I can bet that there might be more interesting implementations, however mine is really good for getting started ;-). BTW, I’m doing this sample based on this article @ http://www.pnpguidance.net/post/UnityConfigurationSeparateConfigurationFile.aspx I’m going to try to sum up all the step I’ve followed to create this (Unity) plug in. At the end of the post (or sample) the source code will be published for download.
Project Structure
The following are the projects that have been created, and the (relevant) files that each project contains.
Sample.UnityPlugin This is the default project (in this case a console application). This project uses the plug in implementation, although it does not need to know how is the concrete implementation, this project only references to the Sample.UnityPlugin.Contracts.
Sample.UnityPlugin.Contracts This project contains common content between the plug in contract and the plug in implementation. This common content is an interface (aka Contract) which defines what the plugin must provide. This project is referenced by the two parts, the first part if the part of the application that will implement the functionality of the plug in. The second part is the part of the application that will be using the implementation of the plug in.
Sample.UnityPlugin.Cocoa This project represents the plug in implementation. It references to the Sample.UnintyPlugin.Cocoa in order to know the plugin’s contract.
Now, lets prepare some references:
Sample.UnityPlugin needs to reference the Microsoft.Practices.Unity, Microsoft.Practices.Unity.Configuration, Sample.Unity.Contracts.
Sample.UnityPlugin.Cocoa only needs to reference to Sample.UnityPlugin.Contracts.
Defining the Plug in Contract
To implement our plug in lets start by defining the Contract (interface) in our Sample.UnityPlugin.Contracts project. The following is the contract file:
namespace Sample.UnityPlugin.Contracts
{
public interface IProvider
{
object Connection { get; }
string Name { get; }
}
}
The IProvider only defines a “Connection” and a Name. Really simple, isn’t ?
Implementing the plug in
The concrete implementation of the plug in will be in the Sample.UnityPlugin.Cocoa (sorry, I was thinking in a Cocoa provided when I wrote this). So, our concrete implementation will be:
using Sample.UnityPlugin.Contracts;
namespace Sample.UnityPlugin.Cocoa
{
public class Provider : IProvider
{
public Provider(string providerName)
{
this.Name = providerName;
}
public object Connection { get; set; }
public string Name { get; set; }
}
}
As you might notices the implementation references the contract (aka interface), and implements the behavior for this contract.
Consuming the plugin
Now lets add the unity.config file to the Sample.UnityPlugin application. The Unity configuration can be loaded from a configuration file, o being set by code.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>
<unity>
<typeAliases>
<typeAlias alias="string" type="System.String, mscorlib" />
<typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />
<typeAlias alias="IProvider" type="Sample.UnityPlugin.Contracts.IProvider, Sample.UnityPlugin.Contracts" />
<typeAlias alias="Provider" type="Sample.UnityPlugin.Cocoa.Provider, Sample.UnityPlugin.Cocoa" />
</typeAliases>
<containers>
<container name="container">
<types>
<type type="IProvider" mapTo="Provider" >
<lifetime type="singleton" />
<typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration">
<constructor>
<param name="providerName" parameterType="string">
<value value="The big Cocoa Provider (tm)"/>
</param>
</constructor>
</typeConfig>
</type>
</types>
</container>
</containers>
</unity>
</configuration>
In a quick review this configuration file is in charge of making the connection between contract and the concrete implementation, by doing it in a configuration file.
It can be changed any time (by providing the correct files). Please, notices that the configuration file is able to call the Provider constructor and send custom values to it.
Also the application is able to label relations between contracts and implementations, and group them into a container, which can be labeled too.
The last comment is about the location of this file, this file uses Configuration API, so it can be referenced indirectly by your app.config (or web.config), however in this sample it’s being loaded
and referenced directly in the code.
Now lets write our main code that will load the plug in:
using System.Text;
using Microsoft.Practices.Unity;
using System.Configuration;
using Microsoft.Practices.Unity.Configuration;
using Sample.UnityPlugin.Contracts;
namespace Sample.UnityPlugin
{
class Program
{
private static IUnityContainer GetContainer()
{
var map = new ExeConfigurationFileMap();
map.ExeConfigFilename = "unity.config";
var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
var section = (UnityConfigurationSection)config.GetSection("unity");
var container = new UnityContainer();
section.Containers["container"].Configure(container);
return container;
}
static void Main(string[] args)
{
IUnityContainer container = GetContainer();
var myProvider = container.Resolve<IProvider>();
System.Console.WriteLine("Provider Name:{0}", myProvider.Name);
System.Console.ReadKey();
}
}
}
Get container function will load our custom plugin, and the main function will make use of it.
At this time, this post is quite big, and certainly there is more things that unity can do. I’ll try to provide a plug in implementation using MEF, but in my next post 😉
BTW, I almost forgot … here is the source code (Visual Studio 2010 and Unity 2 beta)
https://github.com/hmadrigal/playground-dotnet/tree/master/MsDotNet.PluginWithUnity
Herberth