Reflection.Net: how to load dependencies? - c#

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).

Related

How can I embed a dll to the output assembly with codedom, and use it as reference using C#?

I have a class library dll which my generated program will use e.g. like this DLL.Do.Something(1); So I have to add this dll to codedom to embed it in the program and set it as reference. But I dont know how to do this and nobodí helped me yet...
there are some confussing things in this question.
- do you have a third party dll? why cant you just reference it normally?
- you could use Assembly object to dinamilally load the dll into your domain without it being stringly referenced as:
Assembly assembly = Assembly.LoadFrom(sPath);
the you can get Types from that assembly and also use activator to create instances
but to be honest, this questions is too vague
good luck

C# can't find assembly which is already loaded

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...

Add DLL programmatically at runtime

Using C#, I create a DLL at runtime and now I want to add it as a reference to my project at runtime.
I tried using the LoadFrom method, but it doesn't work.
How can I do this?
First you should load the dll
Assembly assembly = Assembly.LoadFrom("dllPath");
Then you may need to add the assembly to the app domain
AppDomain.CurrentDomain.Load(assembly.GetName());
After that you can load any type from this assembly
Type t = assembly.GetType("typeName");
Then using reflection you can execute methods on this type
Note that you may need to add the below in the configuration file.
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="dlls folder"/>
</assemblyBinding>
</runtime>
LoadFile vs. LoadFrom
Be careful - these aren't the same
thing.
LoadFrom() goes through Fusion and can
be redirected to another assembly at a
different path but with that same
identity if one is already loaded in
the LoadFrom context. LoadFile()
doesn't bind through Fusion at all -
the loader just goes ahead and loads
exactly* what the caller requested. It
doesn't use either the Load or the
LoadFrom context. So, LoadFrom()
usually gives you what you asked for,
but not necessarily. LoadFile() is for
those who really, really want exactly
what is requested. (*However, starting
in v2, policy will be applied to both
LoadFrom() and LoadFile(), so
LoadFile() won't necessarily be
exactly what was requested. Also,
starting in v2, if an assembly with
its identity is in the GAC, the GAC
copy will be used instead. Use
ReflectionOnlyLoadFrom() to load
exactly what you want - but, note that
assemblies loaded that way can't be
executed.)
LoadFile() has a catch. Since it
doesn't use a binding context, its
dependencies aren't automatically
found in its directory. If they aren't
available in the Load context, you
would have to subscribe to the
AssemblyResolve event in order to bind
to them.
ref Suzanne Cook's .NET CLR Notes
Use Assembly.LoadFile method and then run code inside it using reflection.
Actually Assembly.Load is usually what you'd want, not LoadFrom and not LoadFile:
Which context is right for you? In
general, I strongly recommend that you
use the Load context whenever possible
http://blogs.msdn.com/b/suzcook/archive/2003/05/29/57143.aspx
You cannot add dll to a project when project is already running. However, you can load the dll using Assembly.LoadFrom( filename). Normally such scenerio is used for SOA or plugin based projects. You can use interface to specify the type structure and load the dll and use it.
You could use the Assembly.LoadFrom method to dynamically load an assembly at runtime.
This is very simple in .NET: http://msdn.microsoft.com/en-us/library/1009fa28.aspx

Indirectly accessing an assembly through reflection

OK, I have the following bit of code:
Assembly assembly = Assembly.LoadFile("W:\\AssemblyFoo.dll");
foreach (Type type in assembly.GetExportedTypes())
{
foreach (object attribute in type.GetCustomAttributes(false)) //Exceptio on that line
{
string attributeString = attribute.ToString();
}
}
The code throws the following exception: Could not load file or assembly 'AssemblyBar, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
The problem is that one of the attribute is in AssemblyBar, which is referenced by AssemblyFoo, but not directly by the current's project (ProjectBaz) assembly. I'd rather avoid referencing AssemblyBar directly in ProjectBaz, since AssemblyFoo is selected by the user. What's the correct way to go about this ? I'm pretty sure I'm missing something easy.
I know it's possible since Reflector does it.
Mono's Cecil
You may circumvent the problem by not loading the assemblies through the built-in reflection
facilities, using a tool like Mono.Cecil instead. I've had good experiences in applying it for analysis tasks.
From the Cecil site:
with Cecil, you can load existing
managed assemblies, browse all the
contained types, modify them on the
fly and save back to the disk the
modified assembly.
CCI Metadata
As an alternative to Cecil, you might consider CCI Metadata by Microsoft Research. I have not used that tool, so I can not comment on how it stacks up to Cecil.
Hope this helps.
You could include AssemblyBar in you bin directory so that the clr can load it.
MemberInfo.GetCustomAttributesData() was introduced in .NET 4 so that you could examine custom attributes without having to instantiate them.
UPDATE: Taking closer look at MemberInfo.GetCustomAttributesData(), although it doesn't instantiate the attributes, it still need to load the assembly. My apologies.
Another possible route to investigate would be Mono Cecil. You can load the Mono.Cecil assembly and use it with the .NET Framework, not just Mono. It is much more powerful than System.Reflection and Reflection.Emit. According to its homepage:
Cecil does not need to load the assembly or have compatible assemblies to introspect the images.
This sounds exactly like what you're trying to do.

include assemblies via code? C#

In msvc i can write
#pragma comment(lib, "my.lib");
which includes my.lib in the linking stage. In my solution i have 2 projects. One is a class project the other is my main. How do i include the reference dll in code instead of adding the reference in the project?
Contrary to popular belief, it is possible :-)
To statically link .NET assemblies check out ILMerge. It's a utility that can be used to merge multiple .NET assemblies into a single one. Be it an executable or a DLL.
You could create a batch script that packages your assemblies together as a post-build step.
Edit: One thing to note however is that this does not remove the need to reference the library. The reference is still needed in order to compile your code that is dependent the external types. Much like including header files under C(++). By default c# assemblies are independent, there is no linking involved. However the tool I mentioned above allows you to create a new assembly with the external dependencies included.
As far as I know, you can't. If you need to access type that are included in a non referenced assembly, you'll have to use Assembly.Load().
I'm afraid you can't.
You can dynamically load the assembly via Assembly.Load(...) but then you have use reflection to explicitly create each Type you need to use.
I don't think you can include a dll from code without adding a reference. What you can do however is to use reflection to load that assembly and use a type from that assembly.
Assembly.Load() will get you a handle on the assembly and then you should be able to iterate through the types in the assembly.
Managed code doesn't use a linker. The C/C++ equivalent of a reference assembly is the #include directive, you need that in C/C++ to allow the compiler to generate code for an external type. Exact same thing in C#, you can't use an external type unless the compiler has a definition for it. The reference assembly supplies that.
The equivalent of C/C++ linking is done at runtime in a managed program. The JIT compiler loads assemblies as needed to generate machine code.
One thing you can do in a C# program that you can't do in a C/C++ program is using Reflection. It allows you to invoke a constructor and call a type's methods with type and method names as strings. Start that ball rolling with Assembly.GetType() and the methods of the Type class. However, consider a plug-in model with, say, the System.AddIn namespace first.
If you want to load an assembly at runtime, you can use Assembly.LoadFrom(filePath). But that way you are not referencing the assembly, and you can't use strong typing.
For example, you can have different plugins implementing a known interface (the one which is in a separate, referenced assembly), and have them all placed in a folder. Then you can check the folder and load all implementing classes at runtime (like in this example).

Categories

Resources