Pregunta

Escenario

Tengo dos envoltorios alrededor de Microsoft Office, uno para 2003 y otro para 2007. Dado que tener dos versiones de Microsoft Office ejecutándose una al lado de la otra no es "oficialmente posible". ni recomendado por Microsoft, tenemos dos cajas, una con Office 2003 y la otra con Office 2007. Compilamos los contenedores por separado. Los archivos DLL están incluidos en nuestra solución, cada casilla tiene el pago y envío same pero con Office 2003 o 2007 " descargado " por lo que no intenta compilar esa DLL en particular. De lo contrario, se generarán errores en la compilación debido a que las DLL COM de Office no están disponibles.

Utilizamos .NET 2.0 y Visual Studio 2008.

Hechos

Dado que Microsoft cambió misteriosamente la API de Office 2003 en 2007, renombrando y cambiando algunos métodos ( suspiro ) para que no sean compatibles con versiones anteriores, necesitamos los dos contenedores. Tenemos cada máquina de compilación con la solución y una DLL de Office activada. Por ejemplo: la máquina con Office 2003 tiene la "Office 2007" DLL descargado, por lo tanto, no lo compila. La otra caja es la misma idea pero al revés. Todo esto porque no podemos tener 2 Office diferentes en la misma caja para fines de programación. (técnicamente podría tener dos Office juntas según Microsoft) pero no para la programación y no sin algunos problemas.

Problema

Cuando cambiamos la versión de la aplicación (por ejemplo, de 1.5.0.1 a 1.5.0.2) necesitamos recompilar la DLL para que coincida con la nueva versión de la aplicación, esto se hace automáticamente, ya que el contenedor de Office está incluido en la solución . Dado que los contenedores están contenidos en la solución, estos heredan la versión de la aplicación, pero tenemos que hacerlo dos veces y luego "copiar". la otra DLL a la máquina que crea el instalador. (Un dolor & # 8230;)

Pregunta

¿Es posible compilar una DLL que funcione con cualquier versión de la aplicación, a pesar de ser "más antigua"? He leído algo sobre los manifiestos, pero nunca he tenido que interactuar con ellos. Cualquier puntero será apreciado.

La razón secreta de esto es que no hemos cambiado nuestros envoltorios en '' edades '' y tampoco Microsoft con sus antiguas API, sin embargo, estamos volviendo a compilar la DLL para que coincida con la versión de la aplicación en cada versión que hacemos. Me gustaría automatizar este proceso en lugar de tener que confiar en dos máquinas.

No puedo eliminar la DLL del proyecto (ninguno de ellos) porque hay dependencias.

Podría crear un tercer '' master wrapper '' pero aún no lo he pensado.

¿Alguna idea? ¿Alguien más con el mismo requisito?

ACTUALIZACIÓN

Aclarando:

Tengo 1 solución con N proyectos.

" Aplicación " + Office11Wrapper.dll + Office12Wrapper.dll.

Ambos " envoltorios " usar dependencias para la aplicación + otras bibliotecas en la solución (capa de datos, capa comercial, marco, etc.)

Cada contenedor tiene referencias para el paquete de Office respectivo (2003 y 2007).

Si compilo y no tengo instalado Office 12, recibo errores de Office12Wrapper.dll que no encuentran las bibliotecas de Office 2007. Entonces, lo que tengo son dos máquinas de construcción, una con Office 2003, una con Office 2007. Después de una actualización completa de SVN + compilación en cada máquina, simplemente usamos office12.dll en el "instalador". para que el contenedor se compile con el "mismo código, la misma versión".

Nota: Office 2007 Build Machine tiene el Contenedor para Office 2003 "descargado" y viceversa.

Gracias de antemano.

¿Fue útil?

Solución

Cuando el solucionador de ensamblados .NET no puede encontrar un ensamblado al que se hace referencia en tiempo de ejecución (en este caso, no puede encontrar la versión DLL de envoltorio particular con la que se vinculó la aplicación), su comportamiento predeterminado es fallar y esencialmente bloquear la aplicación. Sin embargo, este comportamiento se puede anular conectando el evento AppDomain.AssemblyResolve. Este evento se desencadena cuando no se puede encontrar un ensamblaje al que se hace referencia y le brinda la oportunidad de sustituirlo por otro ensamblado en lugar del que falta (siempre que sean compatibles). Entonces, por ejemplo, podría sustituir una versión anterior de la DLL del contenedor que cargue usted mismo.

La mejor manera de hacerlo es agregar un constructor estático en la clase principal de la aplicación que engancha el evento, por ejemplo:

using System.Reflection;

static Program()
{
    AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs e)
    {
        AssemblyName requestedName = new AssemblyName(e.Name);

        if (requestedName.Name == "Office11Wrapper")
        {
            // Put code here to load whatever version of the assembly you actually have

            return Assembly.LoadFile("Office11Wrapper.DLL");
        }
        else
        {
            return null;
        }
    }
}

Al colocar esto en un constructor estático de la clase de aplicación principal, se garantiza que se ejecutará antes de que cualquier código intente acceder a cualquier cosa en el archivo DLL envoltorio, asegurando que el enlace esté en su lugar antes de tiempo.

También puede usar archivos de políticas para redirigir versiones, pero eso suele ser más complejo.

Otros consejos

Solo una idea: ¿podría usar TlbExp para crear dos ensamblajes de interoperabilidad (con diferentes nombres y ensamblajes) y utilizar una interfaz / fábrica para codificar los dos a través de su propia interfaz? Una vez que tenga el dll de interoperabilidad, no necesita la dependencia COM (excepto, por supuesto, para realizar pruebas, etc.).

TlbImp tiene una / asmversion para la versión, por lo que podría hacerse como parte del script de compilación; pero estoy seguro de que incluso necesitas esto: solo asegúrate de que "la versión específica" es falso en la referencia (explorador de soluciones)?

Además, sé que no ayuda, pero C # 4.0 con dynamic y / o " No PIA " podría ayudar aquí (en el futuro; tal vez).

No estoy seguro de seguir completamente todo lo que dijiste, pero déjame intentarlo:

Parece que tiene una solución con 2 (?) proyectos. Una es la aplicación real y la otra es un contenedor para la API de Office. Su aplicación tiene una referencia de proyecto a su contenedor API de Office. Nunca antes había programado para la oficina, pero parece que las API de programación son un componente común del que solo puede tener una versión en una máquina (es decir, 2003 o 2007, no ambas). Y tal vez aquí es donde está el problema, pero debido a que tiene una referencia de proyecto, el contenedor se compilará primero, se copiará en el directorio bin de su aplicación, donde su aplicación se vinculará a esa compilación del contenedor. Esto hará que el manifiesto de la aplicación solicite específicamente esa versión del contenedor en tiempo de ejecución.

Si tuviera el contenedor en una solución separada y agregara una referencia a la biblioteca compilada en lugar del proyecto, siempre vincularía su aplicación a esa versión del contenedor y podría evitar el problema.

Otra opción posible es la redirección de enlace de ensamblaje. Esto es más avanzado y viene con su propio conjunto de problemas, pero puede leerlo aquí .

O similar a la idea de Marc, podría extraer una interfaz y extraer algunos objetos comunes en una biblioteca de Framework, y codificar su aplicación contra la interfaz y los objetos comunes. Luego, en tiempo de ejecución, use la reflexión para cargar el ensamblaje e instanciar el contenedor que desee.

Creo que la clave es eliminar la dependencia del proyecto si puedes. Parece que el contenedor es bastante estable y no está cambiando, de lo contrario no pediría vincularlo a una versión anterior.

Instalar Office 2003 y 2007 en paralelo en la misma máquina es definitivamente posible - Lo hacemos en nuestra organización incluso en estaciones de trabajo de producción para usuarios finales.

En ese artículo vinculado, Microsoft recomienda que no lo haga para uso real. Pero en su caso, parece ser solo para una sola máquina de compilación, es decir, no va a usar ninguna versión de Office en esa máquina. En este contexto, trataría de ver si puede hacer que la instalación en paralelo funcione.

Mi suposición podría estar equivocada, y está intentando hacer esto para la máquina de cada desarrollador. En ese caso, debe ignorar esta respuesta :-)

¡Buen trabajo de detective! Acabo de armar una implementación basada en el concepto presentado anteriormente, y funciona de maravilla:

static Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args)
{
     string partialName = args.Name.Substring(0, args.Name.IndexOf(','));
     return Assembly.Load(new AssemblyName(partialName));
}

Por supuesto, hay margen de mejora, ¡pero esto me sirve!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top