Con C#, y gracias a System.AppDomain extender la
funcionalidad de una aplicación mediante plugins es un juego de niños.
Una forma un tanto bruta de hacerlo, es considerar que los plugins son
programas externos que ejecutan una serie de acciones necesarias y
pueden devolver un valor (en forma de archivo en disco). Un ejemplo de
este tipo de plugins lo tenemos en la implementación de los plugins
para el programa de edición gráfica GIMP (GNU Image Manipulation
Program), el cual se vale de multitud de pequeños plugins en forma de
programas ejecutables que se utilizan para aplicar filtros o efectos a
una imagen.
En este caso, vamos a hacer un programa muy sencillo que funcione como un servidor de aplicaciones,
de forma que dos o más aplicaciones se puedan lanzar simultáneamente en
diferentes hilos, lo que permite aprovechar los procesadores multicore
ejecutando cada aplicación en cores distintos.
Forma de uso del ejemplo: Se crean dos proyectos de consola, se copia
el código fuente del servidor en uno, y el del programa ejemplo en
otro. Una vez creados se generan los dos, y se copian a la carpeta raíz
( C:\ ), y se ejecuta el programa servidor. Éste incrustará dos copias
del programa ejemplo, que imprime cierto número de veces su
identificador de ejecución único, y se podrá observar cómo los
resultados impresos por cada programa se van intercalando gracias al
paralelismo de usar hilos.
Para los más perezosos, incluyo como adjunto al artículo un zip con los proyectos y el código fuente que he utilizado (nota: el formato de los archivos de proyecto es de Visual Studio 2008, aunque el código fuente en sí funciona perfectamente con Visual Studio 2005!!)
Servidor (programa que incrusta otros programas en hilos):
using System;
using System.Threading;
namespace remoteInvoker
{
class Program
{
static void Main(string[] args)
{
string callingDomainName = Thread.GetDomain().FriendlyName;
Console.WriteLine(”AppDomain Servidor: “+callingDomainName);
crearAplicacion(@”c:\appdomainExperiment.exe”);
crearAplicacion(@”c:\appdomainExperiment.exe”);
Console.WriteLine(”Server: exit”);
Console.ReadKey(true);
}
private static void crearAplicacion(string aplicacion) {
Aplicacion app = new Aplicacion(aplicacion);
}
}
class Aplicacion {
string appName;
public Aplicacion(string aplicacion) {
appName = aplicacion;
Thread appThread = new Thread(new ThreadStart(doWork));
appThread.Start();
}
private void doWork(){
AppDomain dominio = AppDomain.CreateDomain(”serverDomain”);
dominio.ExecuteAssembly(appName);
AppDomain.Unload(dominio);
}
}
}
using System;
using System.Threading;
//using System.Reflection;
namespace remoteInvoker
{
class Program
{
static void Main(string[] args)
{
//Mostrar el AppDomain predefinido.
string callingDomainName = Thread.GetDomain().FriendlyName;
Console.WriteLine(”AppDomain Servidor: “+callingDomainName);
//Invoca al creador de aplicaciones
crearAplicacion(@”c:\appdomainExperiment.exe”);
crearAplicacion(@”c:\appdomainExperiment.exe”);
//Fin
Console.WriteLine(”Server: exit”);
Console.ReadKey(true);
}
/// Crea un hilo que ejecuta una aplicación
private static void crearAplicacion(string aplicacion) {
Aplicacion app = new Aplicacion(aplicacion);
}
}
/// Incrusta un ensamblado en un hilo para ejecutarlo
class Aplicacion {
// Nombre (url) de la aplicación
string appName;
/// Constructor, crea un dominio predeterminado
public Aplicacion(string aplicacion) {
appName = aplicacion;
Thread appThread = new Thread(new ThreadStart(doWork));
appThread.Start();
}
/// Método de ejecución del hilo
private void doWork(){
//Crea un dominio de ejecución para este hilo
AppDomain dominio = AppDomain.CreateDomain(”serverDomain”);
//Ejecuta el ensamblado
dominio.ExecuteAssembly(appName);
//Descarga el Dominio
AppDomain.Unload(dominio);
}
}
}
Programa de Ejemplo:
using System;
using System.Threading;
namespace appdomainExperiment
{
class Program
{
static void Main()
{
System.Console.BackgroundColor = ConsoleColor.Blue;
Console.WriteLine(”Hola Mundo! (Método Principal)”);
Guid k = System.Guid.NewGuid();
for (int i = 0; i < 10; i++)
{
Console.WriteLine(k.ToString());
Thread.Sleep(10);
}
try
{
Console.WriteLine(”AppDomain Cliente: ” +
System.AppDomain.CurrentDomain.DomainManager.EntryAssembly.FullName);
}
catch
{
Console.WriteLine(”AppDomain Cliente: Aplicación independiente”);
}
System.Console.BackgroundColor = ConsoleColor.Black;
}
}
}
Fullbyte Alchemist