As you may know you cannot use ILMerge to merge assemblies with XAML (WPF application) however there is a little known trick you can use to achieve your goal in a bit different way.
- Add needed assemblies as embedded resources in your application
- Load needed assemblies from embedded resources in runtime
How to do this?
First you need to ensure that all referenced assemblies (except the framework itself) are added properly to the application resources on every application build. To do this you can use this simple MSBuild task (AfterResolveReferences) at the end of your project:
...
<
Import
Project
=
"$(MSBuildToolsPath)\Microsoft.CSharp.targets"
/>
<
Target
Name
=
"AfterResolveReferences"
>
<
ItemGroup
>
<
EmbeddedResource
Include
=
"@(ReferenceCopyLocalPaths)"
Condition
=
"'%(ReferenceCopyLocalPaths.Extension)' == '.dll'"
>
<
LogicalName
>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</
LogicalName
>
</
EmbeddedResource
>
</
ItemGroup
>
</
Target
>
...
Now you need to write some code to load needed assemblies from resources when requested. To do this you can define your own entry point for the WPF application, preload all assemblies from resources and return needed assembly using AppDomain.CurrentDomain.AssemblyResolve event:
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Reflection;
namespace
WpfApplication1
{
public
class
Program
{
[STAThreadAttribute]
public
static
void
Main()
{
var assemblies =
new
Dictionary<
string
, Assembly>();
var executingAssembly = Assembly.GetExecutingAssembly();
var resources = executingAssembly.GetManifestResourceNames().Where(n => n.EndsWith(
".dll"
));
foreach
(
string
resource
in
resources)
{
using
(var stream = executingAssembly.GetManifestResourceStream(resource))
{
if
(stream ==
null
)
continue
;
var bytes =
new
byte
[stream.Length];
stream.Read(bytes, 0, bytes.Length);
try
{
assemblies.Add(resource, Assembly.Load(bytes));
}
catch
(Exception ex)
{
System.Diagnostics.Debug.Print(
string
.Format(
"Failed to load: {0}, Exception: {1}"
, resource, ex.Message));
}
}
}
AppDomain.CurrentDomain.AssemblyResolve += (s, e) =>
{
var assemblyName =
new
AssemblyName(e.Name);
var path =
string
.Format(
"{0}.dll"
, assemblyName.Name);
if
(assemblies.ContainsKey(path))
{
return
assemblies[path];
}
return
null
;
};
App.Main();
}
}
}
That’s all!
Enjoy!
Make your XAML development easier, visit
Telerik XAMLFlix for more WPF tutorials and tips!
Download