El ensamblaje no puede encontrar el ensamblaje referenciado cuando se compila en la memoria con codeDOMProvider

StackOverflow https://stackoverflow.com/questions/6804147

Pregunta

Estoy tratando de compilar algún código en la memoria en tiempo de ejecución usando un codeDOMProvider.

El código que estoy compilando tiene una referencia a un ensamblaje externo que incluyo en los parámetros utilizados al compilar el código.

Cuando compilo en la memoria e intento usar la reflexión en el ensamblaje generado en un complemento de Visual Studio, lanza una excepción diciendo que no puede encontrar el ensamblaje referenciado.

(Excepción)
"No se puede cargar uno o más de los tipos solicitados. Recupere la propiedad Loaderexcepciones para obtener más información".

(LoaderException)
"{" No pudo cargar archivo o ensamblaje 'dynamo.jiss.task, versión = 1.0.0.0, cultura = neutral, publickeyToken = null' o una de sus dependencias. El sistema no puede encontrar el archivo especificado. ":" Dynamo.jiss.task, versión = 1.0.0.0, cultura = neutral, publickeyToken = null "}"

He intentado hacer referencia al ensamblaje de diferentes lugares utilizando la ruta absoluta.

El mismo código exacto funciona bien si se ejecuta desde una aplicación de consola, y también funciona bien en el complemento si no compilo en la memoria.
Eliminar la referencia al ensamblaje externo y el código que hace referencia también funciona al compilar la memoria, por lo que probablemente como la excepción describe es un problema con la carga del ensamblaje referenciado.

¿Alguien tiene una idea de por qué compilar la memoria y hacer referencia a un ensamblaje no funciona en un complemento?

¿Hay algunas restricciones dentro del appdomain que se está ejecutando o algo que debería tener en cuenta? (Mi mejor suposición actualmente)

¿Debería estar en una carpeta específica? referenciado usando una ruta relativa? ¿configuraciones de seguridad? ¿Necesita ser firmado? ¿algunas ideas?


Lo que estoy tratando de lograr es una forma de poner archivos con una extensión específica en un proyecto y dejar que el complemento lo compile automáticamente y si implementa una interfaz ITASK (desde el ensamblaje externo) llamará un método de configuración () que lo convierte en Es posible que el código se conecte a los eventos de Visual Studio y ejecute tareas/scripts mientras escucha los diferentes eventos. De esta manera, puedo ejecutar fácilmente plantillas de texto si se cambia otro archivo, o combinar y minificar archivos en diferentes eventos (documento guardado, compilación, etc.).

¿Ya existe algo como esto (para aliviarme del dolor)? :)

¿Fue útil?

Solución

Lo más probable es que esto esté sucediendo porque está diciendo a Codedom que genere un ensamblaje en memoria (que es realmente una mentira ya que se genera temporalmente al disco, lo cargue y luego elimina el archivo). El punto es que el directorio de compilación para el ensamblaje de codeMedom no es el mismo que el que está utilizando para compilarlo. Es decir, si estás ejecutando en bin debug, el ensamblaje de la codificación se está generando en %TEMP %.

Podrías resolver esto de una de dos formas en las que puedo pensar:

  1. Compile el ensamblaje Codedom a la misma ruta que su ensamblaje de ejecución.

    myCodeProvider.GenerateInMemory = false; // may not be necessary...haven't tried this in a while
    myCodeProvider.OutputAssembly = string.Format(@"{0}\{1}", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location, "mydll.dll");
    
  2. Maneje el evento AssemblyResolve y proporcione el ensamblaje codificado el ensamblaje referenciado que se solicita.

    AppDomain.CurrentDomain.AssemblyResolve += OnCurrentDomainAssemblyResolve
    
    private static Assembly OnCurrentDomainAssemblyResolve(object sender, ResolveEventArgs args)
    {
                    // this is absurdly expensive...don't do this more than once, or load the assembly file in a more efficient way
                    // also, if the code you're using to compile the CodeDom assembly doesn't/hasn't used the referenced assembly yet, this won't work
                    // and you should use Assembly.Load(...)
                    foreach (Assembly @assembly in AppDomain.CurrentDomain.GetAssemblies())
                    {
                        if (@assembly.FullName.Equals(args.Name, StringComparison.OrdinalIgnoreCase))
                        {
                            return @assembly;
                        }
                    }
    }
    
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top