Please download to get full document.

View again

of 24
All materials on our website are shared by users. If you have any questions about copyright issues, please report us to resolve them. We are always happy to assist you.
Categories
Published
Creación de aplicaciones con soporte de plugins
  63 Capítulo 2 C# EL HIJO PRÓDIGO DEMICROSOFT ES UNO DELOS FAVORITOS PARADESARROLLO DEAPLICACIONES WEB,WINDOWS Y MOBILE.EN ESTA SECCIÓN SEPRESENTAN PRÁCTICASINTERESANTES PARAREALIZAR EN ESTAPLATAFORMA,APLICABLES ACUALQUIERPROBLEMÁTICA DELMUNDO REAL.  64 El Gran libro del Desarrollador DESARROLLOS EXTENSIBLES CON C# Veremos algunas técnicas que brinda el Framework .NET para escribiraplicaciones capaces de ser extendidas sin recompilar. ctualmente, muchas aplicaciones permitenextender su funcionalidad mediante el usode plugins, es decir, agregados que le otor-gan funcionalidad extra una vez que estáterminada y puesta en producción, sin ne-cesidad de tocar y volver a compilar el código. Desdeel punto de vista del usuario final, esta posibilidad re-presenta una interesante ventaja, ya que le permiteadaptar la aplicación a sus necesidades sin depender denuestra intervención (ideal para programas comercialesde tipo “enlatados”). También tiene ventajas para los desarrolladores de laaplicación, ya que les permite implementar y distribuir mejoras y agregados de una manera realmente muy sencilla.Para ver en detalle todos los conceptos relacionadosa la escritura de aplicaciones con soporte para plugins, vamos a desarrollar un pequeño y simple editor de tex-to, junto con un plugin que agregue la funcionalidadpara contar las palabras que tiene. ¿Qué necesitamos? Para que nuestra aplicación soporte el agregado deplugins, debemos tener en cuenta dos aspectos fun-damentales: primero, los plugins que se desarrollendeben tener acceso a elementos de la aplicación so-bre los cuales trabajar; segundo, el código del plugindebe poder determinarse en tiempo de ejecución de laaplicación (no, en tiempo de compilación), es decir que la aplicación debe estar totalmente desacopladade los plugins que se escriban en el futuro. Para lo-grarlo, vamos a valernos del uso de las interfaces y el late bining (enlace tardío), conceptos que explica-remos a continuación. Las interfaces Para que el plugin pueda conocer algunos elemen-tos de la aplicación y actúe sobre ellos, vamos a escri-bir una interfaz que abstraiga las características de unarchivo de texto, y otra para el editor de texto propia-mente dicho. Con el objetivo de que el plugin pueda ser compilado independientemente de la aplicación, colo-caremos dichas interfaces en un assembly separado.Usando Visual Studio .NET, creamos un nuevo proyec-to de tipo Biblioteca de Clases, agregamos una nuevaclase (cuyo archivo llamaremos IArchivoTexto.cs) y reemplazamos el código generado por el asistente, por este otro: public interface IArchivoTexto{string Nombre{ get; set;}string Texto{ get; set; }bool Grabado{ get; set; }void Grabar();} Esta interfaz representa las carac-terísticas mínimas de un archivo detexto simple. Como dijimos al prin-cipio, el plugin necesita conocer ele-mentos de la aplicación y, también,mostrar mensajes al usuario. Parahacerlo, vamos a escribir una inter-faz que exponga el archivo de textocon el que actualmente se está tra-bajando en la aplicación, y un méto-do para que el plugin muestre men-sajes al usuario. public interface IEditor{IArchivoTexto  Archivo{ get; }void MostrarMensaje( string mensaje, string titulo );} En principio, puede parecer que elmétodo MostrarMensaje no es nece-sario, ya que dentro del código delplugin podemos hacer una invoca-ción a MessageBox.Show con el finde mostrar el mensaje. Sin embargo,ésta no es una buena idea, ya que elplugin queda limitado a aplicacio-nes Winforms. Si quisiéramos, lue-go, utilizarlo en una aplicación de ASP.NET, tendríamos problemas.Mediante el uso de un método, laimplementación final del mecanis-mo para mostrar el mensaje depen-de de la aplicación que utiliza elplugin.Bien, ahora que ya tenemos las in-terfaces necesarias para comunicar laaplicación con el plugin, podemos es-cribir la que se deberá implementar para crear un plugin destinado anuestra aplicación. Como éste debeser accesible desde alguna opción delmenú, la implementación de cadauno debe indicarle a la aplicación quétexto mostrar en la interfaz con elusuario para acceder a su funcionali-dad. Esto lo haremos mediante unapropiedad que llamaremos TextoMe-nu. Para facilitar la configuración(como veremos más adelante), vamosa exigir que el plugin sea capaz de in-formar un nombre que lo distinga en-tre los demás. Por último, necesita-mos pasarle al plugin el contexto deleditor en el cual ejecutarse (usando lainterfaz IEditor) y un método para in- vocar la función provista por el plu-gin. La interfaz IPlugin queda, enton-ces, de esta forma: public interface IPlugin{string Nombre{ get; }string TextoMenu{ get; }IEditor ContextoEditor{ get; set; }void Ejecutar();} Escribir la aplicación  Ya tenemos las interfaces definidas; vamos a comenzar ahora a escribir nuestra aplicación. Usando VisualStudio .NET, creamos un proyecto detipo Aplicación para Windows y agregamos una referencia al que ge-neramos antes. Lo primero que tene-mos que hacer es armar la interfazgeneral de la aplicación. Agregamosun componente MainMenu y creamosdos opciones de menú de nivel supe-rior: Archivo (mnuArchivo) y Plugins(mnuPlugins). Es importante darle al  A Creación de aplicaciones con soporte de plugins  65 2 | C# menú de plugins un nombre que recorde-mos, ya que deberemos referenciarlo másadelante. Agregamos también un TextBox y le establecemos las propiedades MultiLi-ne en true y Dock en Fill. A esta altura, siejecutamos el proyecto, la aplicación se ve-rá como en la [Figura 1] .Luego, vamos a definir una clase que im-plemente la interfaz IArchivoTexto: public class ArchivoTexto: IArchivoTexto{public ArchivoTexto(){texto = string.Empty;nombre = string.Empty;}private bool grabado;private string nombre;private string texto;public string Nombre{get{ return nombre; }set{ nombre = value; }}public string Texto{get{ return texto; }set{ texto = value; }}public bool Grabado{get{ return grabado; }set{ grabado = value; }}public void Grabar(){ // TODO: agregar la implementación  ArchivoTexto.Grabar}} Como vemos, el texto del archivo, simple-mente, será una variable de tipo string. Para no complicar demasiado el ejem-plo, vamos a hacer que el formularioprincipal de la aplicación implemente lainterfaz IEditor, y que contenga todos loselementos necesarios para pasarles a losplugins instalados. Para que el formularioimplemente la interfaz, la agregamos a sudefinición: public class FormEditor : Form, IEditor Como la interfaz IEditor expone una pro-piedad de tipo IArchivoTexto, declaramosun variable de tipo ArchivoTexto, privadaal formulario, e implementamos la propie-dad correspondiente a la interfaz: private ArchivoTexto archivo = new ArchivoTexto();public IArchivoTexto Archivo{get{ return archivo; } } También debemos implementar el métodoMostrarMensaje. Como en este caso se tra-ta de una aplicación Winforms, usamos elclásico MessageBox, con un botón Aceptar  y un icono de información: public void MostrarMensaje(string mensaje, string titulo){MessageBox.Show(mensaje, titulo, MessageBoxButtons.OK, MessageBoxIcon.Information);} Para que el texto del archivo se actualicecon las modificaciones que reraliza elusuario del editor, agregamos un maneja-dor del evento TextChanged del textboxque actualice el texto y marque el archivocomo modificado: private void txtTexto_TextChanged(object sender, System.EventArgs e){archivo.Grabado = false;archivo.Texto = txtTexto.Text;} El plugin Como la aplicación está casi lista, vamosa enfocarnos en la escritura del pluginque, más tarde, agregaremos a la aplica-ción. Como dijimos, el plugin debe ser to-talmente independiente de ésta, por locual lo colocaremos en un ensamblado se-parado, agregando un nuevo proyecto detipo Biblioteca de Clases a nuestra solu-ción. En él hacemos referencia al ensam-blado que creamos al principio y agrega-mos una nueva clase que implemente lainterfaz IPlugin: public class ContadorPalabras: IPlugin{public ContadorPalabras(){}private IEditor editor;public IEditor ContextoEditor{get{ return editor; }set{ editor = value; }}public string Nombre{get{ return ContadorPalabras ; }}public string TextoMenu{get{return Contar Palabras ;}}} Como ven en el código, la clase implementalas tres propiedades de la interfaz. Como nom-bre usaremos “ContadorPalabras” y, en la op-ción del menú de la aplicación, aparecerá eltexto “Contar Palabras”. Si recordamos el có-digo de la interfaz IPlugin, veremos que anuestra nueva clase le falta el método Ejecu-tar. La implementación de este método en elplugin tomará el texto del archivo contenidoen el contexto del editor (que recibe mediantela propiedad ConextoEditor) y, usando el mé-todo Split de la clase String, obtendrá un arre-glo con todas las palabras. Por último, me-diante el método MostrarMensaje, informaráal usuario la cantidad de palabras que contie-ne el texto que está escribiendo en el editor: public void Ejecutar(){ Figura 1. Nuestra aplicación base a la cual se le podran agregar plugins  66 El Gran libro del Desarrollador public ConfiguracionPlugins(){}private ArrayList pluginsInstalados = new ArrayList();public ArrayList PluginsInstalados{get{ return pluginsInstalados; }}}  Ahora que ya tenemos definida la clase para acceder a la confi-guración, debemos escribir clase que se encargue de leer el archi- vo de configuración xml y de crear el objeto correspondiente. Agregamos una nueva clase a nuestro proyecto, la llamamos Con-figuracionPluginsSectionHandler y modificamos su declaraciónpara indicar que implementa la interfaz IConfigurationSection-Handler. Como vimos antes, esta interfaz expone un solo métododenominado Create, que recibe tres parámetros, de los cuales nosinteresa únicamente el último, que, al momento de la invocacióndel método, contiene el nodo XML correspondiente a nuestra sec-ción personalizada. El formato de la sección Como vamos a tener que manipular un poco el documento XML,antes de escribir el código debemos tener bien definido el formatode nuestra sección. Queremos que nuestra aplicación pueda tener muchos plugins instalados, de modo que vamos a crear un elemen-to XML llamado <Plugins>, que podrá contener a uno o más ele-mentos <plugin>. El elemento <plugin> tendrá atributos para in-dicar el nombre de cada uno, el ensamblado donde se encuentra y el nombre de la clase que lo implementa. Nuestra sección persona-lizada quedará de la siguiente manera: <Plugins><Plugin nombre= ContadorPalabras ensamblado= MisPlugins clase= MisPlugins.ContadorPalabras /></Plugins> Pasamos, entonces, a escribir el código del método Create denuestra clase ConfiguracionPluginsSectionHandler. Mediante unaconsulta XPath, vamos a conseguir la lista de nodos <Plugin> y,para cada uno detectado, obtendremos sus atributos, que utilizare-mos para crear, mediante late binding  y relection una instancia deun objeto IPlugin y agregarlo a la lista de plugins del objeto Con-figuracion. Para poder usar reflection, debemos agregar a nuestraclase una cláusula using System.Reflection. El código del métodoCreate queda así: public object Create(object parent, object configContext, System.Xml.XmlNode section){ConfiguracionPlugins config = new ConfiguracionPlugins();XmlNodeList plugins = section.SelectNodes( ./Plugin );foreach(XmlNode nodo in plugins){string nombre = nodo.Attributes[ nombre ].Value;string ensamblado = nodo.Attributes[ ensamblado ].Value;string clase = nodo.Attributes[ clase ].Value;if( editor == null )throw new NullReferenceException( No se ha establecido el contexto donde se aplica el plugin );if( editor.Archivo == null )throw new NullReferenceException( No se ha establecido el archivo para trabajar );int cantidadPalabras = 0;if( editor.Archivo.Texto.Trim().Length > 0 ){string[] palabras = editor.Archivo.Texto.Split(' ');cantidadPalabras = palabras.Length;}editor.MostrarMensaje(string.Format( Cantidad de palabras: {0} , cantidadPalabras), Contador de Palabras );}  Ya tenemos listo el editor de texto y, también, nuestro primer plu-gin, pero aún no hay forma de indicarle a la aplicación qué plu-gins queremos agregar. Configuración de plugins Para que la aplicación reconozca los plugins, vamos a agregar una sección al archivo de configuración, donde indicaremos losnombres y la ubicación de cada uno de los que queremos utilizar. Antes de continuar, agregaremos un archivo de configuración anuestra aplicación principal, utilizando el asistente de Visual Stu-dio, que incorporará al proyecto un archivo llamado App.Config.Por predefinición, los valores que podemos agregar al archivo deconfiguración son pares de la forma llave y valor, que deben ir ubi-cados dentro del tag <appSettings>. Para nuestro caso, esta opciónno es suficiente, ya que tenemos más datos para configurar. Afortu-nadamente, el framework .NET nos provee de un mecanismo por elcual podemos escribir nuestras propias secciones dentro del archivode configuración, y nos ofrece una clase que se encarga de leer esasección y “traducirla” para que la aplicación pueda utilizar esos da-tos de configuración. La forma de hacerlo es implementando la in-terfaz System.Configuration.IConfigurationSectionHandler. Esta ex-pone un único método que recibe un nodo XML con el elemento denuestra sección personalizada del archivo de configuración, y debedevolver un objeto que represente los datos de configuración.Entonces, debemos escribir una clase que represente los datos dela configuración. Para simplificar el ejemplo, la nuestra sólo ten-drá una lista de los plugins instalados: public class ConfiguracionPlugins{ Definición Late binding (o “enlace tardío”) es la habilidad de crearinstancias de objetos cuyo tipo real no se conoce entiempo de compilación, pero sí, en tiempo de ejecución.La técnica de late binding permite utilizar objetoscreándolos a partir del nombre de la clase al quepertenecen, lo cual dota a las aplicaciones de una granflexibilidad. Cuando el tipo real del objeto se conoce entiempo de compilación, se trata de un “early binding” (o“enlace temprano”).
We Need Your Support
Thank you for visiting our website and your interest in our free products and services. We are nonprofit website to share and download documents. To the running of this website, we need your help to support us.

Thanks to everyone for your continued support.

No, Thanks
SAVE OUR EARTH

We need your sign to support Project to invent "SMART AND CONTROLLABLE REFLECTIVE BALLOONS" to cover the Sun and Save Our Earth.

More details...

Sign Now!

We are very appreciated for your Prompt Action!

x