usando ILMerge con le librerie .NET 4

Due problemi:

1) Assemblaggio .NET di base non incluso nell’assembly ILMerged

Ho problemi ad usare ILMerge nel mio post-build dopo l’aggiornamento da .NET 3.5 / Visual Studio 2008 a .NET 4 / Visual Studio 2010. Ho una soluzione con diversi progetti il ​​cui framework di destinazione è impostato su “.NET Framework 4” . Io uso il seguente comando di ILMerge per unire le singole DLL di progetto in una singola 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 

Se si omette di specificare la posizione della directory framework .NET 4, viene visualizzato un errore “Riferimento assembly non risolto: Sistema” da ILMerge. Se si omette di specificare il percorso della directory MSTest, viene visualizzato un errore “Riferimento assembly non risolto: Microsoft.VisualStudio.QualityTools.UnitTestFramework”.

Il comando ILMerge sopra funziona e produce una DLL. Quando faccio riferimento a quella DLL in un altro progetto .NET 4 C #, tuttavia, e provo a utilizzare il codice al suo interno, viene visualizzato il seguente avviso:

    Il riferimento principale “MyILMergedDLL” non può essere risolto perché ha una dipendenza indiretta sull’assembly .NET Framework “mscorlib, Version = 4.0, Culture = neutral, PublicKeyToken = b77a5c561934e089” che ha una versione superiore “4.0.65535.65535” rispetto alla versione “4.0.0.0” nel framework di destinazione corrente.

    Se poi rimuovo /targetplatform:v4 flag e provo a usare MyILMergedDLL.dll, ottengo il seguente errore:

    Il tipo ‘System.Xml.Serialization.IXmlSerializable’ è definito in un assembly a cui non viene fatto riferimento. È necessario aggiungere un riferimento all’assembly ‘System.Xml, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089’.

    Non sembra che dovrei farlo. Chiunque utilizzi la mia API MyILMergedDLL.dll non dovrebbe aggiungere riferimenti a qualsiasi libreria a cui fa riferimento. Come posso aggirare questo?

    2) TypeLoadException Only When Using Assembly unito

    Modifica: oltre a questo, anche se aggiungo un riferimento a System.Xml nel progetto consumer che utilizza MyILMergedDLL.dll, l’utilizzo di un codice in MyILMergedDLL.dll fornisce questa eccezione:

    System.TypeLoadException: imansible caricare il tipo ‘System.Func`2’ dall’assembly ‘MyILMergedDLL, Version = 1.0.1.1, Culture = neutral, PublicKeyToken = …’.

    Questo è il codice nel mio progetto di consumo; la linea che ha causato il TypeLoadException è la seconda:

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

    Il particolare costruttore di TypeLoadException che genera il TypeLoadException è definito in una class pubblica in MyILMergedDLL e quando utilizzo questo costruttore quando si fa riferimento alle singole DLL del progetto, funziona correttamente. È solo quando utilizzo questo costruttore quando faccio riferimento alla DLL unita a IL che ottengo l’eccezione. Non so cosa sta succedendo.

    Ecco il costruttore:

     public Row(IEnumerable keys) : base(keys) { } 

    E la base a cui si riferisce ha questo codice:

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

    C’era una versione molto recente per risolvere i problemi di x64. Mettiti in contatto direttamente con Mike Barnett se hai ancora problemi (mbarnett su microsoft dot com)


    Addendum. C’è qualcosa di molto, molto sbagliato /lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319" . Ultimamente, questo problema ha provocato un sacco di programmatori nei guai, dopo che .NET 4.5 è stato rilasciato. Quella directory non è quella corretta per gli assembly di riferimento .NET 4.0. Il suo contenuto viene sovrascritto con i 4,5 assembly, non è più ansible utilizzarlo per il targeting di un’installazione di .NET 4.0. L’errore di runtime che si ottiene è molto imbarazzante, il programma non riesce più a trovare determinati tipi. Di solito bombardamenti sull’attributo [Estensione], a volte sull’interfaccia ICommand.

    Questi tipi e alcuni altri sono stati spostati da un gruppo all’altro. L’utilizzo dei gruppi di riferimento corretti è un requisito indispensabile. Devi usare:

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

    Regola per abbinare la tua particolare macchina e la versione del framework di destinazione.

    Ecco la “Post Build String” per Visual Studio 2010 SP1, utilizzando .NET 4.0. Sto creando un file .exe della console con tutti i file sub-.dll inclusi.

     "$(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 

    Suggerimenti di base:

    • Si noti la directory “\ deploy \”: questo è dove finisce il file .exe di output.
    • Si noti la directory “ILMerge \”. Ho copiato l’utility ILMerge nella directory della mia soluzione (così ho potuto distribuire la fonte senza dovermi preoccupare di documentare l’installazione di ILMerge).

    Suggerimenti avanzati:

    Se hai problemi con esso non funziona, aggiungi un “echo” prima del comando “Post Build”. Quindi, aprire la finestra “Output” in Visual Studio (View..Output) e verificare il comando esatto effettivamente generato da Visual Studio. Nel mio caso particolare, il comando esatto era:

     "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 

    Aggiornare

    Aggiunto questo al mio passaggio “Post Build”, sostituisce tutti i file .exe + .dll con un singolo .exe combinato. Mantiene anche il file .pdb di debug intatto:

     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 

    Altre alternative:

    • Combinazione di più assiemi in un singolo EXE per un’applicazione WPF .
    • .Net Reactor .
    • SmartAssembly (un’alternativa commerciale piuttosto costosa).

    Puoi anche aggiungere un file di configurazione con il seguente:

           

    Preso da qui

    Basta impostare i riferimenti PresentationCore e PresentationFramework per avere “Copia Local = True” nella finestra delle proprietà di Visual Studio (dopo aver selezionato i riferimenti in Solution Explorer). Risolverà il problema senza hard-coding il percorso del framework. Preferisco questa soluzione perché il percorso è diverso a seconda che il server di sviluppo / build sia a 64 bit o 32 bit e cambierà inevitabilmente quando verranno rilasciate nuove versioni .NET / VS.

    Per coloro che utilizzano ILMerge dalle attività della comunità in .csproj:

      

    Abbiamo un parco misto di agenti di compilazione di elementi di configurazione, quindi utilizziamo la variabile di ambiente $ (ProgramFiles) per indicare il percorso corretto (unità + cartella x86 / x64), come raccomandato da MSBuild Team .