MEF Creación de Aplicaciones Extensibles

MEF es un componente que se ha introducido en el framework 4.0 y que en mi opinión es un gran desconocido y que nos va a permitir diseñar aplicaciones extensibles sin ningún esfuerzo extra, de manera que incluso terceros podrán extender la aplicación en tiempo de ejecución sin necesidad de recompilar ni reiniciar la aplicación. Un buen ejemplo es Seesmic con todos sus plugins. No es que Microsoft haya inventado la rueda esto ya lo hacíamos antes con una serie de patrones, en este caso lo que han hecho es facilitar su implementación.

Mucha gente confunde MEF con Ioc y no es lo mismo, MEF utiliza internamente Ioc, en mi opinión , cada uno resuelve problemas distintos. Ioc esta orientado al desacoplamiento entre  componentes y MEF tiene como objetivo la extensibilidad de nuestra aplicación, pero bueno esto daría para muchas discusiones asi que vamos a centrarnos en MEF y para ello lo mejor como siempre un ejemplo.

MEF se basa en un Catalogo, es decir que extensiones (plugins) tengo y un CompositeContainer que es el contenedor de estos plugins y se encarga de instanciarlos y resolver referencias. el ejemplo que propongo es muy sencillo vamos a tener una listbox donde cargaremos nuestras extensiones  y que al seleccionar una de ellos mostrar un mensaje cada una en un idioma diferente, vamos un hola mundo.

Lo primero que tenemos que hacer es definir el contrato que van a tener los plugins que queremos en nuestra aplicación, esto es un requisito importante cada plugin que hagamos, este debe de cumplir una interfaz. En nuestro ejemplo creamos un proyecto donde generaremos esta Interfaz, le daremos de nombre HelloWorldMEFContract que contendrá una interfaz en este caso tan sencilla como

1 public interface HelloWorldContract 2 { 3 //Nombre del plugin 4 string Name { get; } 5 //Metodo que devolvera hola en el idioma del plugin 6 string Hello(); 7 }

Una vez tenemos definida nuestra interface para el plugin vamos a ir construyendo estos plugins , para lo que añadiremos un proyecto por cada uno de ellos, en este caso voy a hacer dos plugins uno para castellano y otro para ingles. A cada proyecto le añadimos como referencia el assembly de la interface anterior y la clase la hacemos que implemente la interface HelloWorldContract.

 

1 public class HolaMundo :HelloWorldContract 2 { 3 #region HelloWorldContract Members 4 5 public string Name 6 { 7 get 8 { 9 return "Plugin Spanish"; 10 } 11 12 } 13 14 public string Hello() 15 { 16 return "Hola"; 17 } 18 19 #endregion 20 }

 

Hasta aquí nada de MEF, pero para que este plugoin sea utilizado por MEF lo primero que tenemos que hacer es añadir la referencia System.ComponentModel.Composition una vez añadimos ponemos como atributo de la clase HolaMundo Export que indicara que sea clase es un plugin que MEF tiene que recoger.

1 [Export(typeof(HelloWorldContract))] 2 public class HolaMundo :HelloWorldContract 3 { 4 #region HelloWorldContract Members 5 6 public string Name 7 { 8 get 9 { 10 return "Plugin Spanish"; 11 } 12 13 } 14 15 public string Hello() 16 { 17 return "Hola"; 18 } 19 20 #endregion 21 }

De esta manera iremos definiendo los plugins que queramos, en nuestro caso el de Ingles quedaría

 

1 [Export(typeof(HelloWorldContract))] 2 public class HelloWorld:HelloWorldContract 3 { 4 #region HelloWorldContract Members 5 6 public string Name 7 { 8 get { return "Plugin English"; } 9 } 10 11 public string Hello() 12 { 13 return "Hello"; 14 } 15 16 #endregion 17 } 18

Ahora vamos a implementar la parte consumidora de estos plugins para lo que crearemos una aplicación WPF la cual tendrá una ventana donde añadiremos un combo y un TextBlock. Para consumir los plugins podemos realizar la carga de un assembly o de varios a la vez. Lo logico es crear una carpeta plugins y copiar todos nuestro plugins en este directorio y realizar la carga indicando ese directorio que es lo que vamos a realizar nosotros.

Lo primero que tenemos que hacer es definir una lista donde vamos a realizar la carga de todos los plugins que consuman ese interface.

 

 

1 [ImportMany(typeof(HelloWorldContract))] 2 private IList<HelloWorldContract> pluginsHello = new List<HelloWorldContract>(); 3

 

Si os fijais hemos puesto el atributo ImportMany de manera que todos los assemblys que contenga ese interfaz los va a cargar en esa lista, el cuando lo vemos mas adelante. Como hemos dicho que vamos a cargar todos los plugins de la carpeta “plugin” utilizaremos el metodo DirectoryCatalog , pero vamos a ver el proceso entero en el código.

 

1 public partial class MainWindow : Window 2 { 3 [ImportMany(typeof(HelloWorldContract))] 4 private IList<HelloWorldContract> pluginsHello = new List<HelloWorldContract>(); 5 6 public MainWindow() 7 { 8 InitializeComponent(); 9 10 InitiateMEF(); 11 Loaded += new RoutedEventHandler(MainWindow_Loaded); 12 } 13 14 private void InitiateMEF() 15 { 16 // crea el catalogo con los tipos que tengan el atributo export de los assemblies de la carpeta plugins 17 DirectoryCatalog catalog = new DirectoryCatalog("Plugins"); 18 19 // Crea el contenedor para el catalogo 20 CompositionContainer container = new CompositionContainer(catalog); 21 22 // Aqui MEF llena la variables pluginsHello con los tipos que cumpla HelloWroldContract 23 24 try 25 { 26 container.ComposeParts(this); 27 } 28 catch (CompositionException compositionException) 29 { 30 MessageBox.Show(compositionException.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error); 31 } 32 }

 

Si os fijáis en el código cuando se llama a ComposeParts es cuando crea todas las clases del catalogo en la lista que hemos declarado con el atributo ImportMany

El siguiente paso es utilizar ya los plugins, en nuestro ejemplo cargaremos el combo con la propiedad Name de los plugins.

1 void MainWindow_Loaded(object sender, RoutedEventArgs e) 2 { 3 foreach (HelloWorldContract plugin in pluginsHello) 4 { 5 cbIdioma.Items.Add(plugin.Name) ; 6 7 } 8 if (cbIdioma.Items.Count > 0) 9 { 10 cbIdioma.SelectedIndex = 0; 11 } 12 13 }

En el evento SelectionChanged invocaremos al método Hello para que muestro Hola en el idioma correspondiente

1 void cbIdioma_SelectionChanged(object sender, SelectionChangedEventArgs e) 2 { 3 foreach (HelloWorldContract plugin in pluginsHello) 4 { 5 if (cbIdioma.SelectedValue.ToString() == plugin.Name) 6 { 7 tbHello.Text = plugin.Hello(); 8 } 9 10 } 11 }

Como veis es muy sencillo utilizar este Framework y nos posibilita de realizar nuestras aplicaciones extensibles.

 

  

Aqui os dejo el código es un zip que contiene un rar, soy un enrevesado

Download File – Code

7 comentarios sobre “MEF Creación de Aplicaciones Extensibles”

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *