2012-09-26 20 views
11

Estoy intentando detener mi aplicación bloqueando archivos DLL en mi directorio de complemento MEF para poder sobrescribir los ensamblados en tiempo de ejecución (nótese que en realidad no estoy tratando de tener MEF recargar ellos sobre la marcha, en el siguiente inicio de la aplicación está bien, simplemente no quiero tener que detener la aplicación para hacer la copia)MEF y ShadowCopying DLL para poder sobrescribirlos en tiempo de ejecución

Estoy tratando de hacer esto creando un dominio de aplicación de copia sombra para mis ensamblados mef cargados de la siguiente manera:

[Serializable] 
    public class Composer:IComposer 
    { 
     private readonly string _pluginPath; 
     public Composer(IConfigurePluginDirectory pluginDirectoryConfig) 
     { 
      _pluginPath = pluginDirectoryConfig.Path; 
      var setup = new AppDomainSetup(); 
      setup.ShadowCopyFiles = "true"; // really??? is bool not good enough for you? 
      var appDomain = AppDomain.CreateDomain(AppDomain.CurrentDomain.FriendlyName + "_PluginDomain", AppDomain.CurrentDomain.Evidence, setup); 

      appDomain.DoCallBack(new CrossAppDomainDelegate(DoWorkInShadowCopiedDomain));  
     } 

     private void DoWorkInShadowCopiedDomain() 
     { 
      // This work will happen in the shadow copied AppDomain. 

      var catalog = new AggregateCatalog(); 
      var dc = new DirectoryCatalog(_pluginPath); 
      catalog.Catalogs.Add(dc); 
      Container = new CompositionContainer(catalog); 
     } 

     public CompositionContainer Container { get; private set; } 
    } 

y luego acceder a mi catálogo de componentes MEF a través del CompositionContainer en esta clase. Sin embargo, el contenedor de composición parece que solo se inicializó dentro del dominio shadowcopy (lo cual tiene sentido) y esto significa que es nulo en mi dominio de aplicación. Me preguntaba si hay una mejor manera de hacer esto o alguna forma de consultar dominios cruzados para obtener mis componentes MEF

+2

Parece que podría simplemente llamar a File.Copy en todos los archivos en el directorio del complemento, utilizando su propio directorio oculto creado manualmente. Luego solo carga desde la ruta de sombra en su dominio principal. –

+0

Pensé en esto, pero tengo entendido que este es el problema que se supone que debe resolver el copiado en la sombra (por lo que probablemente tengan más casos extremos cubiertos con esto). ¿Sabes si la copia oculta es más grande que esto o si la copia manual es lo suficientemente buena? –

+0

@DanBryant basado en las respuestas que he recibido. Siento que esta es la mejor solución para nosotros, si la publicas como respuesta antes de que termine la recompensa, te otorgaré la recompensa. –

Respuesta

-2

Tiene la opción de no usar un catálogo de directorios y usar AssemblyCatalog para cargar todos los ensamblajes en el directorio ? Incluso puede ir al código plex y copiar el mismo código de la clase DirectoryCatalog que lee a través del directorio y carga los ensamblajes.

Perdería la capacidad de cargarlos sobre la marcha, pero como mencionó, no es realmente un requisito.

+0

Hola, @zync quizás me esté perdiendo lo que quieres decir, pero ¿cómo puedo solucionar el problema de copia sombra/aplicación de dominio cruzado mediante la implementación de mi propio DirecoryCatalog. ¿Hay alguna forma de decirle que saque de un dominio de aplicación separado? quizás podría agregar algunos detalles más sobre lo que quiere decir –

+0

@LukeMcGregor - mi sugerencia no funcionará. Pero investigué un poco y esto no es específicamente un problema de MEF. El dominio de aplicación está bloqueando los ensamblajes tocados. http://stackoverflow.com/questions/2745093/overwriting-dlls-in-mef –

+0

Sí, tienes razón, mi problema no es específicamente un problema MEF, es más un problema de copia sombra/appdomain. –

-1

Este escenario está más cerca de la función de actualización automática en aplicaciones móviles. Básicamente, desea recoger ensamblajes nuevos si están disponibles en Inicio/Reiniciar de la aplicación.

Una forma de diseñar esto podría ser tener un mecanismo de comunicación para indicarle a su aplicación al comienzo que hay nuevos ensamblajes disponibles (tal vez un archivo version.txt). En caso afirmativo, el mismo archivo version.txt podría apuntar a la nueva ubicación de los conjuntos. Sí, es posible que termine creando una serie de subcarpetas para señalar la versión correcta, pero podrían ser limpiadas por otro proceso.

podría utilizar una estructura hierarchichal como tal -

Version \ - versión 1.0 \ - Version2.0 \

Este tipo de diseño estaría más cerca de un paradigma bien conocido de actualización automática .

+0

aadde esto como una nueva respuesta porque es un enfoque diferente para resolver el problema general en lugar del problema específico. –

+0

Creo que el enfoque que está sugiriendo es el mismo que la sugerencia anterior de Dan Bryants, para realizar manualmente la misma función que la instantánea. Me siento un poco hacky haciendo esto ya que básicamente clona una función .NET existente. Solo quiero asegurarme de que antes de hacer esto no haya una buena forma de evitar el acceso de dominio cruzado. –

3

Si no quiere seguir la solución de Dan Bryant y zync, puede crear una aplicación de shell que simplemente ejecute su aplicación en un nuevo AppDomain.

Un enfoque sería:

  1. Crear un nuevo proyecto de aplicación que será la aplicación de shell.
  2. En la aplicación de shell, cree AppDomain, habilite la copia oculta y, si lo desea, especifique el directorio donde se habilitará la copia oculta.
  3. Use AppDomain.ExecuteAssembly para llamar a su aplicación actual.

Si en lugar de una aplicación que tiene una biblioteca de clases puede probar lo siguiente:

  1. Crear un nuevo proyecto de biblioteca de clases.
  2. Añadir la siguiente interfaz para el nuevo proyecto de biblioteca de clases:

    public interface IRemoteLoader 
    { 
        void Load(); 
        void Unload(); 
    } 
    
  3. Añadir una implementación de esta interfaz para la biblioteca de clases que necesita para ejecutar en un nuevo dominio de aplicación. En los métodos Load y Unload, debe agregar código para realizar la inicialización y la limpieza, respectivamente. Haz que la clase derive de MarshalByRefObject. Esto es necesario para .NET Remoting para crear objetos proxy en ambos AppDomains.

  4. Después de crear el nuevo dominio de aplicación, utilizar CreateInstanceAndUnwrap para crear una instancia de la clase Loader desde el paso 3.

  5. Utilice la Load y Unload en el objeto creado a partir del paso 4.

Esto será suficiente si no tiene un control preciso y simplemente iniciar/detener es suficiente.

+0

@panosrontogainnis, si, estoy de acuerdo, esta parece ser la forma más soportada de resolver el problema (es decir, bootstrap/shadowcopy toda la aplicación. Desafortunadamente, en mi caso no controlo el bootstrap (ya que estoy en NServiceBus.Hosted) no funcionará específicamente para mí. Habiendo dicho eso, creo que es probablemente la mejor solución para los demás. –

+0

Saludos. Agregué otro enfoque que funciona con bibliotecas de clases. –

Cuestiones relacionadas