Pase y ejecute el delegado en AppDomain separado


Quiero exceute algún pedazo de código en AppDomain separado con delegate. ¿Cómo puedo hacer esto?

UPD1: algunos más detalles sobre mi problema Mi programa de procesamiento de algunos datos (una iteración es: obtener algunos datos de DB, evaluar y crear ensamblados en tiempo de ejecución, ejecutar ensamblados dinámicos y escribir los resultados en DB).

Solución actual: cada iteración se ejecuta en subprocesos separados. Mejor solución: cada iteración se ejecuta en AppDomain separado (para descargar dinámico asseblies).

UPD2: Todos, gracias por las respuestas.

He encontrado uno para mí en este hilo: Proceso de Sustitución.Comienza con AppDomains

Author: Community, 2010-01-05

4 answers

Aunque puedes hacer una llamada a un delegado que será manejada por un AppDomain separado, personalmente siempre he utilizado el método 'CreateInstanceAndUnwrap' que crea un objeto en el dominio de la aplicación extranjera y devuelve un proxy a él.

Para que esto funcione su objeto tiene que heredar de MarshalByRefObject.

Aquí hay un ejemplo:

    public interface IRuntime
    {
        bool Run(RuntimesetupInfo setupInfo);
    }

    // The runtime class derives from MarshalByRefObject, so that a proxy can be returned
    // across an AppDomain boundary.
    public class Runtime : MarshalByRefObject, IRuntime
    {
        public bool Run(RuntimeSetupInfo setupInfo)
        {
            // your code here
        }
    }

    // Sample code follows here to create the appdomain, set startup params
    // for the appdomain, create an object in it, and execute a method
    try
    {
        // Construct and initialize settings for a second AppDomain.
        AppDomainSetup domainSetup = new AppDomainSetup()
        {
            ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
            ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
            ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
            LoaderOptimization = LoaderOptimization.MultiDomainHost
        };

        // Create the child AppDomain used for the service tool at runtime.
        childDomain = AppDomain.CreateDomain(
            "Your Child AppDomain", null, domainSetup);

        // Create an instance of the runtime in the second AppDomain. 
        // A proxy to the object is returned.
        IRuntime runtime = (IRuntime)childDomain.CreateInstanceAndUnwrap(
            typeof(Runtime).Assembly.FullName, typeof(Runtime).FullName);

        // start the runtime.  call will marshal into the child runtime appdomain
        return runtime.Run(setupInfo);
    }
    finally
    {
        // runtime has exited, finish off by unloading the runtime appdomain
        if(childDomain != null) AppDomain.Unload(childDomain);
    }

En el ejemplo anterior, está codificado para ejecutar un método ' Run ' pasando información de configuración y completando el El método Run se determina para indicar que todo el código en el AppDomain hijo se ha completado la ejecución, por lo que tenemos un bloque final que garantiza que el AppDomain se descargue.

A menudo es posible que desee tener cuidado en qué tipos coloca en qué ensamblados: puede usar una interfaz y colocarla en un ensamblado separado del que dependen tanto el llamador (nuestro código que configura el appdomain y lo llama) como el implementador (la clase de tiempo de ejecución). Este IIRC permite que el AppDomain padre para cargar solo el ensamblado que contiene la interfaz, mientras que el appdomain hijo cargará tanto el ensamblado que contiene el tiempo de ejecución como su dependencia (el ensamblado IRuntime). Cualquier tipo definido por el usuario que sea utilizado por la interfaz de IRuntime (por ejemplo, nuestra clase RuntimeSetupInfo) debería normalmente ser colocado en el mismo ensamblado que IRuntime. Además, tenga cuidado de cómo define estos tipos definidos por el usuario : si son objetos de transferencia de datos (como probablemente lo sea RuntimeSetupInfo), probablemente debería marcar ellos con el atributo [serializable] - para que se pase una copia del objeto (serializada desde el appdomain padre al hijo). Desea evitar que las llamadas se marshalled de un appdomain a otro, ya que esto es bastante lento. Pasar DTOs por valor (serialización) significa que acceder a los valores en el DTO no incurre en una llamada de apartamento cruzado (ya que el appdomain hijo tiene su propia copia del original). Por supuesto, esto también significa que los cambios de valor no se reflejan en el appdomain padre DTO original.

Como está codificado en el ejemplo, el appdomain padre terminará cargando tanto los ensamblados IRuntime como Runtime, pero eso se debe a que en la llamada a CreateInstanceAndUnwrap estoy usando typeof(Runtime) para obtener el nombre del ensamblado y el nombre del tipo completamente calificado. En su lugar, podría codificar o recuperar estas cadenas de un archivo, lo que desacoplaría la dependencia.

También hay un método en AppDomain llamado 'DoCallBack' que parece que permite llamar a un delegar en un AppDomain extranjero. Sin embargo, el tipo de delegado que toma es de tipo 'CrossAppDomainDelegate'. La definición de la cual es:

public delegate void CrossAppDomainDelegate()

Por lo tanto, no le permitirá pasar ningún dato en él. Y, como nunca lo he usado, no puedo decirte si hay algún truco en particular.

También, recomendaría buscar en la propiedad LoaderOptimization. Lo que establece esto, puede tener un efecto significativo en el rendimiento, ya que algunos ajustes de esta propiedad fuerzan la nuevo appdomain para cargar copias separadas de todos los ensamblajes (y JIT ellos, etc.) incluso si (IIRC) la asamblea está en el GAC (es decir, esto incluye asambleas CLR). Esto puede darle un rendimiento horrible si utiliza un gran número de ensamblados de su appdomain hijo. Por ejemplo, he usado WPF desde appdomains hijos que causaron grandes retrasos de inicio para mi aplicación hasta que configuré una política de carga más adecuada.

 48
Author: Phil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-05 22:45:03

Para ejecutar un delegado en otro AppDomain puede usar System.AppDomain.DoCallBack () . La página enlazada de MSDN tiene un ejemplo excelente. Tenga en cuenta que solo puede utilizar delegados de tipo CrossAppDomainDelegate.

 8
Author: cdiggins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-14 14:12:56

Necesita leer en . NET Remoting y específicamente en Objetos remotos ya que estos son todo lo que puede pasar a través de AppDomains.

El largo y corto de esto es que su objeto se pasa por valor o por referencia (a través de un proxy).

Por valor requiere que su objeto sea Serializable. Los delegados no son serializables afaik. Eso significa que esta no es una buena ruta a seguir.

Por referencia requiere que usted herede de MarshalByRefObject. De esta manera, la infraestructura remota puede crear el proxy. Sin embargo, también significa que su delegado se ejecutará en la máquina que lo crea, no en el dominio de la aplicación cliente.

Con Todo, va a ser complicado. Es posible que desee considerar hacer que sus delegados sean objetos serializables completos para que puedan moverse fácilmente con la comunicación remota (y funcionen bien con otras tecnologías).

 6
Author: Frank Krueger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-05 20:17:13

Esto no responde a su pregunta directamente, pero tal vez sería mejor crear un servicio WCF o un servicio web en el otro dominio de aplicación para preservar el aislamiento. No conozco su situación particular, pero el diseño arquitectónico aislado es casi siempre el camino correcto.

 3
Author: Andrew Hare,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-05 20:04:12