C# can't find assembly which is already loaded - c#

I am writing an application which uses plugins. Plugins are class libraries which lie in Plug-ins directory. My app loads these libraries via LoadFrom. Some of them have dependencies in the form of libraries which lie in the same Plug-ins directory. When I try to create instance of class from one of plugins via Activator.CreateInstance i recieve an exception 'Unable to find assembly' (this is dependency assembly of plugin), but this assembly is already loaded (!) along with plugins and It is visible in ProcessExplorer.
I can't uderstand in what my trouble is.

Your problem might be, that de loaded assembly isn't the same version as the request one. .Net Runtime maps the Assembly after their name and after their Version if the name equals and the Version differes you get an exception if the other one is loaded, which says "Assembly cann't be found" or something like that. The Problem is, that the assembly could not be matched properly. But there is a solution:
Take a look at the MSDN for further information about that Problem.
Solution for that problem:
If you have to load 2 Versions of that assembly try helping the runtime by implementing the AssemblyResolve Event Samples are also here.
Try using the AssemblyBindLogViewer to determine the dependencies of your plugins and to crosscheck your problem.
I recommend implementing the event anyways if you deal with plugins,
so you can log all assembly requests of that AppDomain.
You will find furhter information about runtime behavior and assembly loading here
Hope i could help, please give us feedback about your solution!
Configuring the Plugin Folder
Load the Plugins into a seperat AppDomain which has the pluginfolder as ApplicationBaseTo configure AppDomains see. This is the recomendet solution to load Plugins, becaus you can define the security level of the AppDomain (Sandboxing)
Extend your current AppDomains PrivatePath, so it also searches the Assemblies in this Path. This method is Obsolete!(but does it's job)

You should provide Full Path of assembly files.
class Program
{
static void Main(string[] args)
{
var asmFileName = "test.dll"; // Your plug-in file name
var asmPath = AppDomain.CurrentDomain.BaseDirectory; // Your assemblies's root folder
var asmFullPath = System.IO.Path.Combine(asmPath, asmFileName);
var asm = System.Reflection.Assembly.LoadFrom(asmFullPath);
}
}

I had similar problems and they were usually solved by changing target framework in the project properties...

Related

Finding Globalized Resource files when remotely loading an assembly

Our code uses a "Plugin" model, that remotely loads dll's conforming to a predefined structure IPluginModel that is defined in the main program. The main program itself has several localized forms where the text and placement of the labels in the UI are all changed based on the different localization Thread.CurrentThread.CurrentUICulture.
One thing that we noticed is that any forms or reports from the remotely loaded dll's will never be properly localized. It does not seem to matter where the localization dll's containing the different resources for the plugin are located, either next to the main form, next to the plugin dll, or anywhere else. How would one cause the Assembly to correctly locate its localized resources when the assembly itself is loaded during RunTime of the main program?
I do have code that rather resembles the method used Here, but dont want to have to manually implement the resx against the form itself if at all possible. The code I have is located directly inside the plugin itself and is called whenever the CurrentUICulture is NOT "en-US".
Ideally speaking, what Im looking for is a way to load the pluginName.resources.dll which is directly associated with the plugin I just loaded. I do see the different folders in my main projects bin folder, the es folder contains a main.resources.dll, but simply placing the plugin dll's in that folder did not seem to work last time I tried it, although in theory that could have changed...or I may have done it wrong at the time...
Loading the assembly [code snippet]
private void LoadPlugin(string filePath)
{
bool isValidPlugin = false;
Assembly asm = null;
try
{
asm = Assembly.LoadFrom(Path.Combine(Environment.CurrentDirectory, filePath));
//Do some type checking to make certain this is in fact one of OUR plugins
var p = (IFTLPlugin)Activator.CreateInstance(types[x]);
_plugins.Add(p.Prefix, p);
}
}
Edit: More thoughts on the subject
Is there some way to intercept the loading structure that attempts to resolve the satellite assemblies, an event that I can implement or a function I can override, where I can manually point the code to the correct resource assembly?. I found some things about assembly resolution, but that was for direct loading, not for satellite resources.
As you know perfectly well already, the runtime loads localized resources using a convention, by looking for satellite assemblies (e.g. fr/pluginName.resources.dll).
I think you may be right to think that this issue may be due to a failure to find those satellite assemblies . You could try confirming this using the .NET Framework diagnostics tool fuslogvw.exe. You can also try to deploy your satellite assemblies to the Global Assembly Cache (GAC) as a quick fix (see Installing a Satellite Assembly in the Global Assembly Cache on this page).
If that works, and to help figure out other suitable locations (other than the GAC), the locations inspected by the runtime to look for satellite assemblies are documented as the fallback process here:
http://msdn.microsoft.com/en-us/library/sb6a8618%28v=vs.71%29.aspx
The .NET system, when loading resource assemblies, uses the Thread.CurrentThread.CurrentUICulture, as you pointed out in your question background.
The problem is that each new thread defaults to CultureInfo.InstalledCulture until it is told otherwise.
Have your main code pass the desired culture to the library in your initialization call.
Then have the library set its Thread.CurrentThread.CurrentUICulture (and .CurrentCulture if appropriate) before you load any resources. That would be before any call to InitializeComponent() or TryFindResource(), for example.
This gets the library's thread's cultures aligned with the main program's thread's cultures, regardless of what the OS's ideas about it are.

Chain-referenced assemblies in WPF

today I'd like to know how do you configure your projects in C# WPF which references additional assemblies in a chain. By the "in a chain" I mean something like this:
we have application which refers to assembly Plugin
Plugin assembly refers Resources where resources used by Plugin are located, eg. images
main application does not refers to Resource in any way.
The following image illustrates what I've just said:
The problem is that Resources is not copied to the bin folder of the application, causing Plugin (Ctrl on the image) resources it requires finding failure.
Workaround
There are workarounds for it which are simply to include Resources to references of the main application or use a post-build step and manually copy required files in that step.
Conclusion
Concluding, I'd like to ask how do you deal with that problem. Are the any other solutions besides those I mentioned in workaround section? Am I missing something in the projects' configuration?
Make sure that the output directory in the Plugin project properties is same as the output directory of your application. Otherwise you have to copy files yourself as you do.
Second option would be using embedded resources.
If you load the plugin dynamically from a different folder than the EXE, you can also copy its dependencies to the same folder as the plugin and load those assemblies dynamically, as well. You then need to handle AssemblyResolve so that the already-loaded assemblies will be resolved instead of trying to find new assemblies:
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var domain = (AppDomain)sender;
var assemblies = domain.GetAssemblies();
return assemblies.FirstOrDefault(assembly => assembly.GetName().Name == args.Name.Split(',')[0]);
}
The code above does a version and strong-naming insensitive match; you can implement your own policy here if you want something stricter.

Resolving Assemblies, the fuzzy way

Here's the setup:
A pure DotNET class library is loaded by an unmanaged desktop application. The Class Library acts as a plugin. This plugin loads little baby plugins of its own (all DotNET Class Libraries), and it does so by reading the dll into memory as a byte-stream, then
Assembly asm = Assembly.Load(COFF_Image);
The problem arises when those little baby plugins have references to other dlls. Since they are loaded via the memory rather than directly from the disk, the framework often cannot find these referenced assemblies and is thus incapable of loading them.
I can add an AssemblyResolver handler to my project and I can see these referenced assemblies drop past. I have a reasonably good idea about where to find these referenced assemblies on the disk, but how can I make sure that the Assmebly I load is the correct one?
In short, how do I reliably go from the System.ResolveEventArgs.Name field to a dll file path, presuming I have a list of all the folders where this dll could be hiding)?
When I have used this in the past we have just compared the file name with the part of the ResolveEventArgs.Name that has the name. If you want to be sure that you are loading the exact same version I suppose you could check if the names match, if they do then load the assembly and then check the assemblies full name against the ResolveEventArgs.Name.
something along these lines:
string name = GetAssemblyName (args); //gets just the name part of the assembly name
foreach (string searchDirectory in m_searchDirectories)
{
string assemblyPath = Path.Combine (executingAssemblyPath, searchDirectory);
assemblyPath = Path.Combine (assemblyPath, name + ".dll");
if (File.Exists (assemblyPath))
{
Assembly assembly = Assembly.LoadFrom (assemblyPath);
if (assembly.FullName == args.Name)
return assembly;
}
}
for completeness:
private string GetAssemblyName (ResolveEventArgs args)
{
String name;
if (args.Name.IndexOf (",") > -1)
{
name = args.Name.Substring (0, args.Name.IndexOf (","));
}
else
{
name = args.Name;
}
return name;
}
The Managed Extensibility Framework (MEF) sounds like something that'll solve all your problems. It can scan folders to locate DLLs, resolve dependencies for any depth and manages plug-in composition in general. Each part (or 'plug-in') just has to declare what it needs and what it provides, and MEF takes care of the wiring. If MEF succeeded in taming VS2010's extensibility beast, then it can handle anything.
I've never had luck with AssemblyResolver. I usually do one of these three:
Require plugins not have external references that are not in the GAC. If they bitch, tell them to ILMerge.
Require plugins to dump all their dlls into a known plugin directory. Load all assemblies in that directory into memory.
Require that plugin dependencies exist in a path that is probed by fusion. You can figure out where the binder is looking for assemblies turn on the fusion log (fuslogvw.exe--don't forget to reboot after turning on logging!).

Embedding assemblies inside another assembly

If you create a class library that uses things from other assemblies, is it possible to embed those other assemblies inside the class library as some kind of resource?
I.e. instead of having MyAssembly.dll, SomeAssembly1.dll and SomeAssembly2.dll sitting on the file system, those other two files get bundled in to MyAssembly.dll and are usable in its code.
I'm also a little confused about why .NET assemblies are .dll files. Didn't this format exist before .NET? Are all .NET assemblies DLLs, but not all DLLs are .NET assemblies? Why do they use the same file format and/or file extension?
ILMerge does merge assemblies, which is nice, but sometimes not quite what you want. For example, when the assembly in question is a strongly-named assembly, and you don't have the key for it, then you cannot do ILMerge without breaking that signature. Which means you have to deploy multiple assemblies.
As an alternative to ilmerge, you can embed one or more assemblies as resources into your exe or DLL. Then, at runtime, when the assemblies are being loaded, you can extract the embedded assembly programmatically, and load and run it. It sounds tricky but there's just a little bit of boilerplate code.
To do it, embed an assembly, just as you would embed any other resource (image, translation file, data, etc). Then, set up an AssemblyResolver that gets called at runtime. It should be set up in the static constructor of the startup class. The code is very simple.
static NameOfStartupClassHere()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
}
static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
{
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 Name property on the ResolveEventArgs parameter is the name of the assembly to be resolved. This name refers to the resource, not to the filename. If you embed the file named "MyAssembly.dll", and call the embedded resource "Foo", then the name you want here is "Foo". But that would be confusing, so I suggest using the filename of the assembly for the name of the resource. If you have embedded and named your assembly properly, you can just call GetManifestResourceStream() with the assembly name and load the assembly that way. Very simple.
This works with multiple assemblies, just as nicely as with a single embedded assembly.
In a real app you're gonna want better error handling in that routine - like what if there is no stream by the given name? What happens if the Read fails? etc. But that's left for you to do.
In the rest of the application code, you use types from the assembly as normal.
When you build the app, you need to add a reference to the assembly in question, as you would normally. If you use the command-line tools, use the /r option in csc.exe; if you use Visual Studio, you'll need to "Add Reference..." in the popup menu on the project.
At runtime, assembly version-checking and verification works as usual.
The only difference is in distribution. When you deploy or distribute your app, you need not distribute the DLL for the embedded (and referenced) assembly. Just deploy the main assembly; there's no need to distribute the other assemblies because they're embedded into the main DLL or EXE.
Take a look at ILMerge for merging assemblies.
I'm also a little confused about why .NET assemblies are .dll files. Didn't this format exist before .NET?
Yes.
Are all .NET assemblies DLLs,
Either DLLs or EXE normally - but can also be netmodule.
but not all DLLs are .NET assemblies?
Correct.
Why do they use the same file format and/or file extension?
Why should it be any different - it serves the same purpose!
You can embed an assembly (or any file, actually) as a resource (and then use the ResourceManager class to access them), but if you just want to combine assemblies, you're better off using a tool like ILMerge.
EXE and DLL files are Windows portable executables, which are generic enough to accomodate future types of code, including any .NET code (they can also run in DOS but only display a message saying that they're not supposed to run in DOS). They include instructions to fire up the .NET runtime if it isn't already running. It's also possible for a single assembly to span across multiple files, though this is hardly ever the case.
Note ILMerge doesn't work with embedded resources like XAML, so WPF apps etc will need to use Cheeso's method.
There's also the mkbundle utility offered by the Mono project
Why do they use the same file format and/or file extension?
Why should it be any different - it serves the same purpose!
My 2¢ bit of clarification here: DLL is Dynamic Link Library. Both the old style .dll (C-code) and .net style .dll are by definition "dynamic link" libraries. So .dll is a proper description for both.
With respect to Cheeso's answer of embedding the assemblies as resources and loading them dynamically using the Load(byte[]) overload using an AssemblyResolve event handler, you need to modify the resolver to check the AppDomain for an existing instance of the Assembly to load and return the existing assembly instance if it's already loaded.
Assemblies loaded using that overload do not have a context, which can cause the framework to try and reload the assembly multiple times. Without returning an already loaded instance, you can end up with multiple instances of the same assembly code and types that should be equal but won't be, because the framework considers them to be from two different assemblies.
At least one way that multiple AssemblyResolve events will be made for the same assembly loaded into the "No context" is when you have references to types it exposes from multiple assemblies loaded into your AppDomain, as code executes that needs those types resolved.
https://msdn.microsoft.com/en-us/library/dd153782%28v=vs.110%29.aspx
A couple of salient points from the link:
"Other assemblies cannot bind to assemblies that are loaded without context, unless you handle the AppDomain.AssemblyResolve event"
"Loading multiple assemblies with the same identity without context can cause type identity problems similar to those caused by loading assemblies with the same identity into multiple contexts. See Avoid Loading an Assembly into Multiple Contexts."
I would suggest you to try Costura.Fody. Just don't forget to Install-Package Fody before Costura.Fody (in order to get the newest Fody!)

Reflection.Net: how to load dependencies?

I try to add an addons system to my Windows.Net application using Reflection; but it fails when there is addon with dependencie.
Addon class have to implement an interface 'IAddon' and to have an empty constructor.
Main program load the addon using Reflection:
Assembly assembly = Assembly.LoadFile(#"C:\Temp\TestAddon\Addon.dll");
Type t = assembly.GetType("Test.MyAddon");
ConstructorInfo ctor = t.GetConstructor(new Type[] { });
IAddon addon= (IAddon) ctor.Invoke(new object[] { });
addon.StartAddon();
It works great when addon do not use dependencie.
But if my addon reference and use an another DLL (C:\Temp\TestAddon\MyTools.dll) that is saved near the addon in disk, it fails:
System.IO.FileNotFoundException: Could not load file or assembly 'MyTools.dll' or one of its dependencies.
I do not wants to copy the addons DLL near my executable, how can i do to tell .Net runtime to search in "C:\Temp\TestAddon\" for any dependency?
Note that adding
Assembly assembly = Assembly.LoadFile(#"C:\Temp\TestAddon\MyTools.dll");
do not change anything.
If MyTools.dll is located in the same directory as Addon.dll, all you need to do is call Assembly.LoadFrom instead of Assembly.LoadFile to make your code work. Otherwise, handling the AppDomain.AssemblyResolve event is the way to go.
Have you looked into using an Inversion Of Control container? I use Castle Windsor with an external Boo file that lets me easily extend the applcation without having to recompile or worry about supplying dependencies
You can use reflection to access the private Assembly._GetReferencedAssemblies().
Although, the method could change in a future version of the .NET framework, it doesn't seem likely—ASP.NET heavily depends on it, though it's possible they could move it from mscorlib to System.Web which is the only assembly that I know of from where the method is referred to.
Assembly.LoadFrom works well until I try to use a webService in my addon, I had had a "Unable to cast object of type 'X' to type 'X'" exception.
It's ugly, but i will use Assembly.LoadFile with the AppDomain.AssemblyResolve.
Thanks guys.
Couple of options:
You can attach to AppDomain.AssemblyResolve to help the CLR resolve the assembly.
You could look into isolating add-ins into their own AppDomain (see System.AddIn namespace and this website).

Categories

Resources