A DotNet Raider

My adventures in the .NET world!
posts - 49, comments - 12, trackbacks - 0

My Links

News

Website View Martino Bordin's profile on LinkedIn

Archives

Post Categories

giovedì 5 aprile 2012

Merge di DLL in un’applicazione WPF

Recentemente ho dovuto creare un’applicazione WPF che fosse facilmente distribuibile (leggi: distribuire solo l’exe).

Purtroppo il tool ILMerge non funziona per applicazioni WPF, a causa di problemi con le risorse contenute in esse (esistono comunque tool funzionanti di terze parti, a pagamento).

Seguendo questo post, ho creato un esempio che qui illustro e che potete scaricare qui.

L’applicazione visualizza semplicemente il fullname di due classi presenti in 2 assembly referenziati:

image

 

Per prima cosa è necessario modificare il file di progetto dell’applicazione WPF aggiungendo, dopo “Microsoft.CSharp.targets” , il seguente snippet:

  1. <Target Name="AfterResolveReferences">
  2.     <ItemGroup>
  3.       <EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
  4.         <LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName>
  5.       </EmbeddedResource>
  6.     </ItemGroup>
  7.   </Target>

Semplicemente, andiamo ad indicare di inserire tutti i file referenziati con estensione “.dll” come “emdedded resource” nell’exe principale. In questo modo eviteremo di eseguire a mano l’inclusione dell’ultima versione delle librerie compilate.

Nelle proprietà del progetto, impostiamo il seguente comando da eseguire durante la fase di post-build: “del $(TargetDir)*.dll” per cancellare tutte le librerie presenti nella “bin”, che non ci serviranno più...

image

 

Impostiamo quindi come oggetto di avvio la classe Bootstrapper (potete ovviamente cambiare il nome):

image

 

Questa, infine, è come definita la classe BootStrapper:

  1. public class BootStrapper
  2. {
  3.     [STAThread]
  4.     public static void Main(string[] args)
  5.     {
  6.         AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
  7.         App.Main();
  8.     }
  9.  
  10.     private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
  11.     {
  12.         var executingAssembly = Assembly.GetExecutingAssembly();
  13.         var assemblyName = new AssemblyName(args.Name);
  14.  
  15.         string path = string.Format("{0}.dll", assemblyName.Name);
  16.         if (assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture) == false)
  17.         {
  18.             path = string.Format(@"{0}\\cf4 {1}", assemblyName.CultureInfo, path);
  19.         }
  20.  
  21.         using (var stream = executingAssembly.GetManifestResourceStream(path))
  22.         {
  23.             if (stream == null)
  24.             {
  25.                 return null;
  26.             }
  27.  
  28.             var assemblyRawBytes = new byte[stream.Length];
  29.             stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
  30.             return Assembly.Load(assemblyRawBytes);
  31.         }
  32.     }
  33. }

 

Sostanzialmente ci agganciamo all’evento AssemblyResolve dell’AppDomain corrente, che viene sollevato ogni volta che la risoluzione di un’assembly fallisce, e ritorniamo l’assembly che abbia in canna nelle embedded resources.

Ecco infatti come si presenta il nostro exe “aprendolo” con ILSpy:

image

E’ anche più semplice di usare la riga di comando di ILMerge ! A bocca aperta

posted @ lunedì 1 gennaio 0001 00:00 | Feedback (1) | Filed Under [ WPF VISUAL STUDIO ]

Powered by:
Powered By Subtext Powered By ASP.NET