AppDomain.CurrentDomain.AssemblyResolve asking for a <AppName>.resources assembly? - c#

using the code How to embed a satellite assembly into the EXE file provided by csharptest.net, I've created a custom assembly resolver and embedded my assemblies in my resources.
I can successfully resolve my assemblies used in but somehow AppDomain.CurrentDomain.AssemblyResolve asks for an assembly called 'AppName.resources' specifically "MyProgram.resources, Version=0.15.3992.31638, Culture=en-US, PublicKeyToken=null" which i don't know how to resolve?
I've tried to disable loading my custom assemblies from resources (placed all my assembly dll's in program directory) and just enabled AppDomain.CurrentDomain.AssemblyResolve, but it was still asking for it.
I'm a bit confused about this, will appreciate a lot if you can help me on this.
Here's my code for interested ones;
static Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
Assembly assembly = null;
string name = args.Name.Substring(0, args.Name.IndexOf(','));
if (name == "MyProgram.resources") return null;
else name = string.Format("MyProgram.Resources.Assemblies.{0}.dll", name);
lock (_loadedAssemblies)
{
if (!_loadedAssemblies.TryGetValue(name, out assembly))
{
using (Stream io = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
{
if (io == null)
{
MessageBox.Show("MyProgram can not load one of it's dependencies. Please re-install the program", string.Format("Missing Assembly: {0}", name), MessageBoxButtons.OK, MessageBoxIcon.Error);
Environment.Exit(-1);
}
using (BinaryReader binaryReader = new BinaryReader(io))
{
assembly = Assembly.Load(binaryReader.ReadBytes((int)io.Length));
_loadedAssemblies.Add(name, assembly);
}
}
}
}
return assembly;
}

Answering on my own;
Adding this line to AssemblyInfo.cs solves it and resolver will not get asked for resources any-more.
[assembly: NeutralResourcesLanguageAttribute("en-US", UltimateResourceFallbackLocation.MainAssembly)]
Though this is a work-around should be carefully considered multi-language applications.
More Info:
https://connect.microsoft.com/VisualStudio/feedback/details/526836/wpf-appdomain-assemblyresolve-being-called-when-it-shouldnt
http://blogs.msdn.com/b/kimhamil/archive/2008/11/11/what-does-the-neutralresourceslanguageattribute-do.aspx
http://forums.devshed.com/net-development-87/c-wpf-appdomain-assemblyresolve-being-called-when-it-shouldn-t-669567.html
http://blogs.msdn.com/b/microsoft_press/archive/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition.aspx
This approach fails for machines with non en-US cultures. A better approach is ignoring resources on assembly resolver;
public Assembly Resolver(object sender, ResolveEventArgs args)
{
lock (this)
{
Assembly assembly;
AssemblyName askedAssembly = new AssemblyName(args.Name);
string[] fields = args.Name.Split(',');
string name = fields[0];
string culture = fields[2];
// failing to ignore queries for satellite resource assemblies or using [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.MainAssembly)]
// in AssemblyInfo.cs will crash the program on non en-US based system cultures.
if (name.EndsWith(".resources") && !culture.EndsWith("neutral")) return null;
/* the actual assembly resolver */
...
}
}

My situation was a bit more complex and the above solution did not work for me. (That is changing the AssemblyInfo.cs file)
I have moved all my form and image resources to a seperate dll and the moment any of the images are used the 'filenotfoundexception' exception is thrown.
The important information is the following:
Beginning with the .NET Framework 4, the ResolveEventHandler event is raised for all assemblies, including resource assemblies. See the following reference
https://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve(v=vs.110).aspx
The solution turned out to be very simple. If a resource file is requested in the form 'dllname.resources.dll' always return null;
Here is the event code that I have adapted from other samples found. (I have commented the debugging lines - un-comment them if you have a problem using the code.
Add this line in your class. It is used to prevent loading a dll more than once
readonly static Dictionary<string, Assembly> _libs = new Dictionary<string, Assembly>();
This is the event method.
private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
{
Assembly assembly = null;
string keyName = new AssemblyName(args.Name).Name;
if (keyName.Contains(".resources"))
{
return null; // This line is what fixed the problem
}
if (_libs.ContainsKey(keyName))
{
assembly = _libs[keyName]; // If DLL is loaded then don't load it again just return
return assembly;
}
string dllName = DllResourceName(keyName);
//string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames(); // Uncomment this line to debug the possible values for dllName
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(dllName))
{
if (stream == null)
{
Debug.Print("Error! Unable to find '" + dllName + "'");
// Uncomment the next lines to show message the moment an assembly is not found. (This will also stop for .Net assemblies
//MessageBox.Show("Error! Unable to find '" + dllName + "'! Application will terminate.");
//Environment.Exit(0);
return null;
}
byte[] buffer = new BinaryReader(stream).ReadBytes((int) stream.Length);
assembly = Assembly.Load(buffer);
_libs[keyName] = assembly;
return assembly;
}
}
private static string DllResourceName(string ddlName)
{
if (ddlName.Contains(".dll") == false) ddlName += ".dll";
foreach (string name in Assembly.GetExecutingAssembly().GetManifestResourceNames())
{
if (name.EndsWith(ddlName)) return name;
}
return ddlName;
}

Related

.NET add directory for dependencies at runtime

From my main C# application i instantiate another application via reflection.
assembly.CreateInstance( ... )
however this other assembly relies on DLLs which are in another directory than the executing assembly. how can i add this directory to the lookup path?
Here is how we implement this need in NDepend.PowerTools. These are a set of tools based on NDepend.API. The DLL NDepend.API.dll is in the directory .\Lib while the NDepend.PowerTools.exe assembly is inn the directory .\.
The NDepend.PowerTools.exe Main() method looks like:
[STAThread]
static void Main() {
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolverHelper.AssemblyResolveHandler;
MainSub();
}
// MainSub() is here to avoids that the Main() method uses something
// from NDepend.API without having registered AssemblyResolveHandler
[MethodImpl(MethodImplOptions.NoInlining)]
static void MainSub() {
...
And the AssemblyResolverHelper class is:
using System;
using System.Diagnostics;
using System.Reflection;
namespace NDepend.PowerTools {
internal static class AssemblyResolverHelper {
internal static Assembly AssemblyResolveHandler(object sender, ResolveEventArgs args) {
var assemblyName = new AssemblyName(args.Name);
Debug.Assert(assemblyName != null);
var assemblyNameString = assemblyName.Name;
Debug.Assert(assemblyNameString != null);
// Special treatment for NDepend.API and NDepend.Core because they are defined in $NDependInstallDir$\Lib
if (assemblyNameString != "NDepend.API" &&
assemblyNameString != "NDepend.Core") {
return null;
}
string binPath =
System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) +
System.IO.Path.DirectorySeparatorChar +
"Lib" +
System.IO.Path.DirectorySeparatorChar;
const string extension = ".dll";
var assembly = Assembly.LoadFrom(binPath + assemblyNameString + extension);
return assembly;
}
}
}
This works within a single AppDomain. I wouldn't use an extra AppDomain here if not needed. AppDomain is a pretty costly facility (in terms of performance) + the thread that jumps the AppDomains boundaries, has to serialize/unserialize in/out data to feed your assembly code, and this can be a headache.
The only advantage of AppDomain is that it lets unload loaded assemblies. So if you expect load/unload assemblies on a regular basis within the life of your main AppDomain, using some extra temporary AppDomain is the way to go.

Could not load file or assembly SharpDX

I use easyhook and SharpDX to get fps data from a DirectX game. Sometimes it works. However, when I start it next time (maybe just some minutes later), it throws the exception System.IO.FileNotFoundException: Could not load file or assembly SharpDX.
When I restart it for several times, it can work. Why? Does anyone have the same problems as mine?
SharpDX version:2.4.2
I don't use EasyHook, but the following code should work for you too. Instead of using ILMerge, which has some limitations, do the following:
1) Link the signed copiy of SharpDx.dll and all other needed SharpDx assemblies to your project. Set the "Local Copy" property to "False".
2) Add those libraries to your project (as you would with .cs files) and set the properties of the files to "Embedded Resource" and "Don't copy to output folder". Make sure those files are exactly the same you linked in step 1.
3) After injecting, first call the following function in your entrypoint, which loads arbitrary assemblies (managed or unmanaged) from your resources if found.
private static void LoadAssemblyFromResources() {
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
try {
Assembly asm = Assembly.GetExecutingAssembly();
string name = args.Name.Substring(0, args.Name.IndexOf(',')) + ".dll";
string rsc = asm.GetManifestResourceNames().FirstOrDefault(s => s.EndsWith(name));
if (rsc == null) return null; //assembly not found in resources
byte[] module;
using (Stream stream = asm.GetManifestResourceStream(rsc)) {
if (stream == null) return null;
module = new byte[stream.Length];
stream.Read(module, 0, module.Length);
}
try {
return Assembly.Load(module); //Load managed assembly as byte array
} catch (FileLoadException) {
string file = Path.Combine(Path.GetTempPath(), name);
if (!File.Exists(file) || !module.SequenceEqual(File.ReadAllBytes(file)))
File.WriteAllBytes(file, module);
return Assembly.LoadFile(file); //Load unmanaged assembly as file
}
} catch {
return null;
}
};
}

How to load a DLL file to determine its dependent assembly names?

At run time I want to load an assembly and need to find the names of its dependent assemblies, so that I can determine which assemblies are required to execute the given DLL file.
You'll need to load the assembly (DLL file) into a Reflection-Only context.
After that you can use GetReferencedAssembles to find dependencies.
I used this some time ago in a nasty bit of code:
Where you load your assembly, register the resolve event:
AppDomain.CurrentDomain.AssemblyResolve += Assemblies_AssemblyResolve;
Assembly.LoadFile("<path to your assembly>");
AppDomain.CurrentDomain.AssemblyResolve -= Assemblies_AssemblyResolve;
The resolve event handler is called for every referenced dll. here i try to load the assembly.
Assembly Assemblies_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.RequestingAssembly != null)
{
return LoadAssemblyFromPath(new AssemblyName(args.Name), args.RequestingAssembly.Location);
}
if (assemblyTryPath != null)
{
return LoadAssemblyFromPath(new AssemblyName(args.Name), assemblyTryPath);
}
return null;
}
And a little helper where the actual loading happens:
private Assembly LoadAssemblyFromPath(AssemblyName assemblyName,string fullPath)
{
if (assemblyName == null||fullPath==null)
return null;
string path = Path.GetDirectoryName(fullPath);
string dllName = assemblyName.Name + ".dll";
string fullPath2Try = Path.Combine(path, dllName);
Assembly loadedAssembly = Assembly.LoadFrom(fullPath2Try);
return loadedAssembly;
}
Hope, that helps!
I found answer. If we want to find the Referenced assemblies of unloaded assembly, we can find from following way.
Assembly _Assembly = Assembly.ReflectionOnlyLoadFrom(#"H:\Account.dll");
AssemblyName[] _AN = _Assembly.GetReferencedAssemblies();

AssemblyResolve event fires when calling Assembly.Load(byte())

So I have a WPF project that is pulling in dlls that are used by another project here at my job. It's a mess of dependencies, I've been using the technique here: http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application to embed the dependencies into a single executable.
Now, when I'm calling a specific method inside one of the dependencies, I hit the AssemblyResolve event. My OnResolveAssembly event runs, it finds the assembly as an embedded resource (cool!), and does "return Assembly.Load(assembyRawBytes)". If I hit F11 at this point (with a breakpoint at the beginning of OnResolveAssembly), I get another call into the same event. It's for the same assembly too (args.Name is the same).
If I let this run I hit a stack overflow, since I can never seem to escape this recursive event calling.
The MSDN docs don't really say when Assembly.Load can fail, except with a FileNotFoundException or BadImageFormatException.
I've tried unhooking the OnResolveAssembly at the moment before I call Assembly.Load, but then my application dies a mysterious death, even under VS it just goes poof.
I'm probably breaking several rules here, but some ideas of where to start looking for problems would be welcome.
I'm going to start poking around in the problematic DLL to see if there are hints about what is wrong with it (maybe it's a mixed assembly?).
Here's my OnResolveAssembly handler:
private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
AssemblyName assemblyName = new AssemblyName(args.Name);
string path = assemblyName.Name + ".dll";
if (assemblyName.CultureInfo.Equals(System.Globalization.CultureInfo.InvariantCulture) == false)
{
path = String.Format(#"{0}\{1}", assemblyName.CultureInfo, path);
}
using (Stream stream = executingAssembly.GetManifestResourceStream(path))
{
if (stream == null)
return null;
byte[] assemblyRawBytes = new byte[stream.Length];
stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
assemblyDictionary.Add(assemblyName.Name, Assembly.Load(assemblyRawBytes));
return assemblyDictionary[assemblyName.Name];
}
}
For the time being, I've resolved it by iterating through all of my resources and attempting Assembly.Load on them, and storing them in a dictionary for retrieval (during the OnResolveAssembly event):
[STAThread]
public static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
Assembly executingAssembly = Assembly.GetExecutingAssembly();
string[] resources = executingAssembly.GetManifestResourceNames();
foreach (string resource in resources)
{
if (resource.EndsWith(".dll"))
{
using (Stream stream = executingAssembly.GetManifestResourceStream(resource))
{
if (stream == null)
continue;
byte[] assemblyRawBytes = new byte[stream.Length];
stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
try
{
assemblyDictionary.Add(resource, Assembly.Load(assemblyRawBytes));
}
catch (Exception ex)
{
System.Diagnostics.Debug.Print("Failed to load: " + resource + " Exception: " + ex.Message);
}
}
}
}
App.Main();
}
private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
AssemblyName assemblyName = new AssemblyName(args.Name);
string path = assemblyName.Name + ".dll";
if (assemblyDictionary.ContainsKey(path))
{
return assemblyDictionary[path];
}
return null;
}
It seems be working fine now (the "failing" assembly will load fine in my second snippet), but I'd be interested to learn why it doesn't work in the first.
Loading an assembly from byte[] is a good way to end up in .dll hell (the place you go for too many/complex dependencies). Problem here is that although you loaded the dll to an AppDomain it is not automatically resolved, when you need it again for dependent types.
I commented on this problem here: AssemblyResolve Does not fire
Long story short, Assemblies are loaded into different "contexts" inside of AppDomains. The context used by Load(byte[]) does not resolve Assemblies automatically.
The solution is keeping track of the loaded assemblies and returning the already loaded assembly instead of loading it a second time. There is a starting point to this approach in my answer to:
Need to hookup AssemblyResolve event when DisallowApplicationBaseProbing = true
But I think you got it right with your workaround.
BTW. Loading an assembly twice is a way to get identical but incompatible types. Ever cast an object of MyType from MyAssembly into MyType from the very same assembly and got null?
That's a warm "Welcome to .dll hell".

Embedding DLL's into .exe in in Visual C# 2010

I'm working on a C# program that uses iTextSharp.dll and WebCam_Capture.dll. When I build the program, it creates executable in the debug folder and it also copies these two dll's to the debug folder as expected. I want to merge them into a single executable, however I failed. These two libraries are visible in the references normally in the solution explorer. I also add them as resources. Executable size got bigger which equals the sum of three files, nevertheless the executable still requires these libraries in its directory... I played with "build action" property of the resource files but no change. I also tried ILmerge but it gave me an error. so what should I do?
Update: This is what I get from ILmerge:
An exception occurred during merging:
Unresolved assembly reference not allowed: System.Core.
at System.Compiler.Ir2md.GetAssemblyRefIndex(AssemblyNode assembly)
at System.Compiler.Ir2md.GetTypeRefIndex(TypeNode type)
It is just a windows application by the way, a form to be filled and printed as pdf with a photo taken via webcam if available. Thanks all!
You can use ILMerge to merge multiple assemblies together. You've already said you did this, and you've received an error. Though I don't know why, you can use an alternative: if the libraries are open source (and their licenses are compatible with yours), you can download the source code, add it to your project and compile. This will result in a single assembly.
The ILMerge page also lists Jeffrey Richter's blog as yet another alternative to solve your issue:
Many applications consist of an EXE file that depends on many DLL
files. When deploying this application, all the files must be
deployed. However, there is a technique that you can use to deploy
just a single EXE file. First, identify all the DLL files that your
EXE file depends on that do not ship as part of the Microsoft .NET
Framework itself. Then add these DLLs to your Visual Studio project.
For each DLL file you add, display its properties and change its
“Build Action” to “Embedded Resource.” This causes the C# compiler to
embed the DLL file(s) into your EXE file, and you can deploy this one
EXE file.
At runtime, the CLR won’t be able to find the dependent DLL
assemblies, which is a problem. To fix this, when your application
initializes, register a callback method with the AppDomain’s
ResolveAssembly event. The code should look something like this:
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
String resourceName = "AssemblyLoadingAndReflection." +
new AssemblyName(args.Name).Name + ".dll";
using (var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(resourceName)) {
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
Now, the first time a thread calls a method that references a type in
a dependent DLL file, the AssemblyResolve event will be raised and the
callback code shown above will find the embedded DLL resource desired
and load it by calling an overload of Assembly’s Load method that
takes a Byte[] as an argument.
Add the DLL files to your Visual Studio project.
For each file go to "Properties" and set its Build Action to "Embedded Resource"
On your code retrive the resource using the GetManifestResourceStream("DLL_Name_Here") this returns a stream that can be loadable.
Write an "AssemblyResolve" event handler to load it.
Here is the code:
using System;
using System.Collections.Generic;
using System.Reflection;
using System.IO;
namespace WindowsForm
{
public partial class Form1 : Form
{
Dictionary<string, Assembly> _libs = new Dictionary<string, Assembly>();
public Form1()
{
InitializeComponent();
AppDomain.CurrentDomain.AssemblyResolve += FindDLL;
}
private Assembly FindDLL(object sender, ResolveEventArgs args)
{
string keyName = new AssemblyName(args.Name).Name;
// If DLL is loaded then don't load it again just return
if (_libs.ContainsKey(keyName)) return _libs[keyName];
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("YourNamespaceGoesHere." + keyName + ".dll")) // <-- To find out the Namespace name go to Your Project >> Properties >> Application >> Default namespace
{
byte[] buffer = new BinaryReader(stream).ReadBytes((int)stream.Length);
Assembly assembly = Assembly.Load(buffer);
_libs[keyName] = assembly;
return assembly;
}
}
//
// Your Methods here
//
}
}
Hope it helps,
Pablo
I modified Pablo's code a little bit and it worked for me.
It was not getting the DLL's resource name correctly.
IDictionary<string, Assembly> _libs = new Dictionary<string, Assembly>();
public Form1()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
InitializeComponent();
}
// dll handler
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string keyName = new AssemblyName(args.Name).Name;
// If DLL is loaded then don't load it again just return
if (_libs.ContainsKey(keyName)) return _libs[keyName];
using (Stream stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(GetDllResourceName("itextsharp.dll"))) // <-- To find out the Namespace name go to Your Project >> Properties >> Application >> Default namespace
{
byte[] buffer = new BinaryReader(stream).ReadBytes((int)stream.Length);
Assembly assembly = Assembly.Load(buffer);
_libs[keyName] = assembly;
return assembly;
}
}
private string GetDllResourceName(string dllName)
{
string resourceName = string.Empty;
foreach (string name in Assembly.GetExecutingAssembly().GetManifestResourceNames())
{
if (name.EndsWith(dllName))
{
resourceName = name;
break;
}
}
return resourceName;
}
The answer you are looking for:
// To embed a dll in a compiled exe:
// 1 - Change the properties of the dll in References so that Copy Local=false
// 2 - Add the dll file to the project as an additional file not just a reference
// 3 - Change the properties of the file so that Build Action=Embedded Resource
// 4 - Paste this code before Application.Run in the main exe
AppDomain.CurrentDomain.AssemblyResolve += (Object sender, ResolveEventArgs args) =>
{
String thisExe = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
System.Reflection.AssemblyName embeddedAssembly = new System.Reflection.AssemblyName(args.Name);
String resourceName = thisExe + "." + embeddedAssembly.Name + ".dll";
using (var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return System.Reflection.Assembly.Load(assemblyData);
}
};
Check out the AssemblyResolve event on the app domain.
I don't have a sample but you basically check what is asked for and stream back the resource DLL. I believe LinqPAD does this well - you could have a look at Joseph Albahari's implementation with a decompiler etc.
Add this anonymous function code on the top of our application constructor. This will add dll from embedded resource in same project.
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
string resourceName = new AssemblyName(args.Name).Name + ".dll";
string resource = Array.Find(this.GetType().Assembly.GetManifestResourceNames(), element => element.EndsWith(resourceName));
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource))
{
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
I know that topic is old but i'll write it for future persons that will want to use it.
i base on code by userSteve.
i would suggest to change this.
String thisExe = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
into this
String thisExe = System.Reflection.Assembly.GetExecutingAssembly().EntryPoint.DeclaringType.Namespace;
that way it would work even if namespace is different than assembly name
also if you want to use DLL from directory you can use it like that (directory Resources as Example)
String resourceName = thisExe + ".Resources." + embeddedAssembly.Name + ".dll";
if you still can't find where place this code in C# Form application paste it inside file "Program.cs" above line:
Application.Run(new Form_1());
and below lines:
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
You didn't reference using WPF, but if you are, this could be the cause of your error. If not, ILMerge should work fine for you. If you are using WPF, here is a solution that works well:
http://blogs.interknowlogy.com/2011/07/13/merging-a-wpf-application-into-a-single-exe/

Categories