2010-06-02 23 views
49

dos problemas:usando ILMerge con .NET 4 bibliotecas

1) Asamblea Basic .NET no está incluido en la Asamblea ILMerged

estoy teniendo problemas para usar ILMerge en mi post-construir después de actualizar. NET 3.5/Visual Studio 2008 a .NET 4/Visual Studio 2010. Tengo una solución con varios proyectos cuyo marco de destino está configurado en ".NET Framework 4". Yo uso el siguiente comando ILMerge fusionar los archivos DLL de proyectos individuales en un solo archivo DLL:

if not $(ConfigurationName) == Debug 
    if exist "C:\Program Files (x86)\Microsoft\ILMerge\ILMerge.exe" 
    "C:\Program Files (x86)\Microsoft\ILMerge\ILMerge.exe" 
     /lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319" 
     /lib:"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies" 
     /keyfile:"$(SolutionDir)$(SolutionName).snk" 
     /targetplatform:v4 
     /out:"$(SolutionDir)bin\development\$(SolutionName).dll" 
     "$(SolutionDir)Connection\$(OutDir)Connection.dll" 
     ...other project DLLs... 
     /xmldocs 

Si dejo de especificar la ubicación del directorio de marco .NET 4, me sale un "referencia de ensamblado pendiente no permitido: Sistema "error de ILMerge. Si dejo de especificar la ubicación del directorio MSTest, aparece el error "Referencia de ensamblaje no resuelto no permitido: Microsoft.VisualStudio.QualityTools.UnitTestFramework".

El comando ILMerge anterior funciona y genera una DLL. Cuando me refiero a esa DLL en otro proyecto # .NET 4 C, sin embargo, y tratar de usar el código dentro de ella, me sale el siguiente mensaje de advertencia:

The primary reference "MyILMergedDLL" could not be resolved because it has an indirect dependency on the .NET Framework assembly "mscorlib, Version=4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" which has a higher version "4.0.65535.65535" than the version "4.0.0.0" in the current target framework.

si yo elimino la bandera /targetplatform:v4 y trata de usar MyILMergedDLL.dll , Me sale el siguiente error:

The type 'System.Xml.Serialization.IXmlSerializable' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

Parece que no debería tener que hacer eso. Quien use mi API MyILMergedDLL.dll no debería tener que agregar referencias a las bibliotecas a las que hace referencia. ¿Cómo puedo evitar esto?

2) TypeLoadException sólo cuando se utiliza combinada Asamblea

Editar: allá de esto, incluso si lo hago agregar una referencia a System.Xml en el proyecto del consumidor que utiliza MyILMergedDLL.dll, haciendo uso de un código de MyILMergedDLL.dll proporciona esta excepción:

System.TypeLoadException: Could not load type 'System.Func`2' from assembly 'MyILMergedDLL, Version=1.0.1.1, Culture=neutral, PublicKeyToken=...'.

Este es el código en mi proyecto de consumidor; la línea que causó el TypeLoadException es la segunda:

var keys = new[] {"a", "b", "c"}; 
var row = new Row(keys); 

El particular, constructor que lanza el TypeLoadException se define en una clase pública en MyILMergedDLL, y cuando se utiliza este constructor al hacer referencia a las DLL de proyectos individuales, funciona multa. Solo cuando uso este constructor al hacer referencia a la DLL fusionada con IL recibo la excepción. No sé lo que está pasando.

He aquí que el constructor:

public Row(IEnumerable<string> keys) : base(keys) { } 

Y el base a la que se está refiriendo tiene este código:

foreach (string key in keys.Where(
    key => !string.IsNullOrEmpty(key) 
)) 
{ 
    _dic.Add(key, string.Empty); 
} 
+0

Aunque esta pregunta no requiere una alternativa, debo recomendar el uso de [Costura Fody] (http://stackoverflow.com/questions/189549/embedding-dlls-in-a-compiled-executable/20306095#20306095) Funciona a las mil maravillas. El embalaje es tan simple como agregar una referencia NuGet :) – Matthias

Respuesta

47

Hubo un very recent release para resolver problemas x64.Póngase en contacto con Mike Barnett directamente si usted todavía tiene problemas (mbarnett en Microsoft punto com)


Addendum. Hay algo muy, muy incorrecto sobre su opción /lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319". Esto ha estado teniendo muchos programadores en problemas últimamente, después de que se lanzara .NET 4.5. Ese directorio es no el adecuado para los ensamblados de referencia de .NET 4.0. Su contenido se sobrescribe con los ensamblados 4.5, ya no puede usarlo para apuntar a una instalación de .NET 4.0. El error de tiempo de ejecución que obtienes es muy incómodo, el programa ya no puede encontrar ciertos tipos. Suele bombardear el atributo [Extensión], a veces en la interfaz ICommand.

Estos tipos, y algunos otros, se movieron de un ensamblaje a otro. Usar los ensambles de referencia correctos es un requisito difícil. Usted debe uso:

/lib:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0" 

Ajuste para que coincida con la versión de bastidor de la máquina y el objetivo en particular.

+0

Gracias por la información. No puedo decir al mirar en esa página para qué son los lanzamientos: VS 2010, C#, .NET 4, ILMerge? –

+0

No importa, investigando en la página de Mike Barnett, veo que trabaja en ILMerge. :) –

+26

¡SÍ! No descargué ningún nuevo lanzamiento, pero sigo marcando el tuyo como la respuesta correcta (el único en este momento ...) porque me llevó a visitar la página de Mike Barnett donde describió el uso de '/ targetplatform: v4, 'en lugar de'/targetplatform: v4/lib: '. –

21

Aquí está el "Post Build String" para Visual Studio 2010 SP1, utilizando .NET 4.0. Estoy construyendo un .exe de consola con todos los archivos sub-.dll incluidos en él.

"$(SolutionDir)ILMerge\ILMerge.exe" /out:"$(SolutionDir)\deploy\$(TargetFileName)" "$(TargetDir)$(TargetFileName)" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards 

consejos básicos:

  • Aviso el directorio "\ deploy \": aquí es donde el archivo .exe de salida termina.
  • Observe el directorio "ILMerge \". Copié la utilidad ILMerge en mi directorio de solución (para poder distribuir la fuente sin tener que preocuparme de documentar la instalación de ILMerge).

consejos avanzados:

Si tiene problemas con él que no trabaja, añadir un "eco" antes de la "Post Build" de comandos. A continuación, abra la ventana "Salida" en Visual Studio (View..Output) y compruebe el comando exacto que Visual Studio realmente generó. En mi caso particular, el comando exacta fue:

"T:\PhiEngine\CSharp\ILMerge\ILMerge.exe" /out:"T:\PhiEngine\CSharp\Server Side\deploy\NfServiceDataHod.History.exe" "T:\PhiEngine\CSharp\Server Side\NfServiceDataHod\bin\Debug\NfServiceDataHod.History.exe" "T:\PhiEngine\CSharp\Server Side\NfServiceDataHod\bin\Debug\*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards 

actualización

añadido esto a mi paso "Post construir", se reemplazan todos los archivos .exe + .dll con un solo .exe combinado. También mantiene el archivo .pdb depuración intacta:

rem Create a single .exe that combines the root .exe and all subassemblies. 
"$(SolutionDir)ILMerge\ILMerge.exe" /out:"$(TargetDir)$(TargetName).all.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards 
rem Remove all subassemblies. 
del *.dll 
rem Remove all .pdb files (except the new, combined pdb we just created). 
ren "$(TargetDir)$(TargetName).all.pdb" "$(TargetName).all.pdb.temp" 
del *.pdb 
ren "$(TargetDir)$(TargetName).all.pdb.temp" "$(TargetName).all.pdb" 
rem Delete the original, non-combined .exe. 
del "$(TargetDir)$(TargetName).exe" 
rem Rename the combined .exe and .pdb to the original name we started with. 
ren "$(TargetDir)$(TargetName).all.pdb" "$(TargetName).pdb" 
ren "$(TargetDir)$(TargetName).all.exe" "$(TargetName).exe" 
exit 0 
+0

Actualización: Acabo de probar esta cadena en un proyecto bastante complejo con 10 subconjuntos personalizados, y funcionó perfectamente. – Contango

+1

+1 para incluir ILMerge.exe con la solución –

+0

Para aquellos que se fusionan con un .dll como resultado, debe cambiar/destino: exe a/destino: library Y eliminar "$ (TargetDir) $ (TargetFileName)" de lo contrario lo hará cargue el .dll principal allí y en el comodín * .dll dando como resultado un error "ILMerge.Merge: ERROR !!: Duplicate type". – Despertar

2

Otras alternativas:

+0

SmartAssembly puede ser costoso en comparación, pero ¿Cuánto vale tu tiempo? He gastado mucho más dinero en horas facturables que los costos de SmartAssembly para descubrir que las alternativas no funcionan y son imposibles de depurar. Este producto "caro" está respaldado por calidad, facilidad de uso y excelente soporte. –

2

También puede añadir un archivo de configuración con el siguiente:

<?xml version ="1.0"?> 
<configuration> 
    <startup useLegacyV2RuntimeActivationPolicy="true"> 
    <requiredRuntime safemode="true" imageVersion="v4.0.30319" version="v4.0.30319"/> 
    </startup> 
</configuration> 

Tomado de here

+0

¿Dónde colocas este archivo? ¿Cómo lo llamas? – brenjt

+0

si no está presente, debe crear un archivo 'ildasm.exe.config' con el xml que puse en mi respuesta – sebagomez

1

acaba de establecer referencias PresentationCore y PresentationFramework tener "copia local = True" en las propiedades de Visual Studio ventana (después de seleccionar las referencias en el Explorador de soluciones). Solucionará el problema sin codificar el camino del framework. Prefiero esta solución porque la ruta es diferente dependiendo de si el desarrollador/servidor de compilación es de 64 bits o 32 bits e inevitablemente cambiará a medida que se lanzan nuevas versiones de .NET/VS.