Placing CefSharp dependencies into a specific directory - c#

I am trying to create a .net forms application that uses cefsharp, but all of the cefsharp dependencies will be placed and used from a specific directory on the PC(let' s say C:\Chromium)
I have seen some entries but almost all of them are ancient, and using very old versions of cefsharp.
How can I achieve this with cefsharp 96.0.142?
I already tried
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="libs"/>
</assemblyBinding>
but it didn' t work. I tried to put the C:\Chromium directory into the PATH env variable, but it didn' t work either. I always ended up with
System.IO.FileNotFoundException: 'Could not load file or assembly 'CefSharp.WinForms'
like exceptions. It looks like a very easy think to do but i got really stuck.
Any ideas would be really helpful. Thanks in advance
EDIT#1 Code Fragment
this.chromiumComponent = new CefSharp.WinForms.ChromiumWebBrowser();
this.SuspendLayout();
//
// chromiumComponent
//
this.chromiumComponent.ActivateBrowserOnCreation = false;
this.chromiumComponent.Dock = System.Windows.Forms.DockStyle.Fill;
this.chromiumComponent.Location = new System.Drawing.Point(0, 0);
this.chromiumComponent.Name = "chromiumComponent";
this.chromiumComponent.Size = new System.Drawing.Size(800, 450);
this.chromiumComponent.TabIndex = 0;
I reference the CefSharp, CefSharp.Core, CefSharp.WinForms dlls from C:\Chromium directory. My intention is not to load the dlls from a subfolder of the project. Instead of that, I would like to place the dlls to a generic directory(like C:\Chromium) and my app to use them from this directory.

Did you try to use AppDomain.AssemblyResolve event? If some assembly is missing in app output folder then AssemblyResolve event occurs and you can load assembly from different folder.
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
...
}
private static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var requestedName = new AssemblyName(args.Name);
var chromiumDirectory = #"C:\\C:\Chromium";
var assemblyFilename = Path.Combine(chromiumDirectory, requestedName.Name + ".dll");
if (File.Exists(assemblyFilename))
{
return Assembly.LoadFrom(assemblyFilename);
}
return null;
}

Related

ResolveEventHandler not invoked when object is created in new AppDomain

I hope it wouldn't be a duplicate, I see plenty of similar questions, but any of them help can't help me.
I have such Method code in nameofdll.dll:
DllMethod()
{
Assembly assembly = Assembly.GetExecutingAssembly();
Type type = assembly.GetType("Class");
MethodInfo method = type.GetMethod("Method");
object obj = Activator.CreateInstance(type);
method.Invoke(...);
}
and Class - constructor add AssemblyResolver
class Class
{
public Class()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);
}
public void Method()
{...}
private Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{...}
}
Till now AssemblyResolver is invoked when I call metod from my main app.exe which is in the same folder as nameofdll.dll, let's name the folder as mainfolder and also from powershell script in this way:
load dll(mainfolder + nameofdll.dll)
call DllMethod()
Everything works fine, but I have to unload dll which AssemblyResolver had loaded, because Method is called multiple times witch different dlls versions.
So I modified DllMethod() like that:
{
Assembly assembly = Assembly.GetExecutingAssembly();
MethodInfo method = type.GetMethod("Method");
//new part
AppDomainSetup domainSetup = new AppDomainSetup();
domainSetup.ApplicationBase = Path.GetDirectoryName(assembly.Location);
AppDomain Domain = AppDomain.CreateDomain(Class, null, domainSetup);
object obj = Domain.CreateInstanceAndUnwrap(assembly.FullName, Class);
method.Invoke(...);
AppDomain.Unload(Domain);
}
I use
domainSetup.ApplicationBase = Path.GetDirectoryName(assembly.Location);
because BaseDirecotry was powershell folder and CreateInstanceAndUnwrap fails to find nameofdll.dll.
And finally the problem is that everyting is ok when using app.exe, but when I called that dll method from powershell script, the AssemblyResolver wasn't invoked and immediately I got error that it could not load some dlls.
I also try to copy domain setting, and add
AppDomainSetup domainSetup = AppDomain.CurrentDomain.SetupInformation;
where CurrentDomain is domain in which AssemblyResolver works fine before, but it didn't solve the problem.

put together all assemblies and use it as embedded resource in exe

I have one assembly(MyAssembly.dll)(something like wrapper) which has a few references to other assemblies(3rdAssembly1.dll, 3rdAssembly2.dll). These referenced assemblies are embedded into my assembly as embedded resources. In my assembly I have main class(MyClass) which calls some functions from these third-party assemblies. This class has one default constructor where I try to resolve required dependencies as below:
public MyClass{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
}
public static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
{
string source = "MyAssembly.Resources."+args.Name.Remove(args.Name.IndexOf(','))+".dll";
//source = "MyAssembly.Resources.3rdAssembly1.dll"
//source = "MyAssembly.Resources.3rdAssembly2.dll"
Assembly a1 = Assembly.GetExecutingAssembly();
Stream s = a1.GetManifestResourceStream(source);
byte[] block = new byte[s.Length];
s.Read(block, 0, block.Length);
Assembly a2 = Assembly.Load(block);
return a2;
}
Then I try to use my assembly(MyAssembly.dll) as embedded resource in my host app(MyApp.exe) where I also use Resolver function.
static void main(string[] args){
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MainResolver);
MyClass my = new MyClass();
my.DoWork();
}
static System.Reflection.Assembly MainResolver(object sender, ResolveEventArgs args)
{
string source = "MyApp.Resources."+args.Name.Remove(args.Name.IndexOf(','))+".dll";
//source = "MyApp.Resources.MyAssembly.dll"
Assembly a1 = Assembly.GetExecutingAssembly();
Stream s = a1.GetManifestResourceStream(args.Name);
byte[] block = new byte[s.Length];
s.Read(block, 0, block.Length);
Assembly a2 = Assembly.Load(block);
return a2;
}
The problem is my host app doesn't resolve internal assemblies(3rdAssembly1.dll, 3rdAssembly2.dll), because Resolver function in MyClass is never called. The host app tries to resolve all of them and as a result fails. I played around with it and found out that if I exclude MyAssembly.dll from embedded resource and locate it in the same folder with host app, and replace += new ResolveEventHandler(MainResolver) on += new ResolveEventHandler(MyClass.Resolver) in main function then it works!
It is necessary to have one assembly, because I'm going to use it in several apps and I don't want to include all referenced assemblies in all apps every time.
So, my question is how to resolve all dependencies(MyAssembly.dll and all internal ones which are contained in MyAssembly.dll as embedded resources) in host app?
Thanks in advance!
I solved this issue. When the host app runs and doesn't find required assembly, it calls AssemblyResolve event. So, I have to use event handler called MainResolver to load MyAssembly.dll. Then before using methods of MyAssembly.dll, it's necessary to remove it from AssemblyResolve, because the app tries to resolve dependencies using ResolveEventHandler in order which they were added (It calls MainResolver and then Resolver). As a result the host app fails, because it can't find required assemblies in MainResolver. The solution is to reorder ResolveEventHandler or remove MainResolver from AssemblyResolve after it was called. I think that exclude useless handler is easier.
So, I don't need to change anything in MyClass. Everything I need is to add following code in host app before I create instance of MyClass.
static MyApp(){
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MainResolver);
}
static void main(string[] args){
//remove MainResolver
AppDomain.CurrentDomain.AssemblyResolve -= MainResolver;
MyClass my = new MyClass();
my.DoWork();
}
Now it works like a charm!

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/

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

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;
}

Categories