manage memory using marshalbyrefobject - c#

I have a method that performs a search in both the local assembly and in the current directory. It is looking for a class based on the name provided (reflection). However I now want to only load the classes/dlls that I am looking for into memory as opposed to loading them all and selecting the one that I want from it.
I have been told that marshalbyrefobject could be used to do this. [Below is the code I am currently using]
The solution would be to create 2 app domains and have one load all the assembiles and do the checks then unload on of the app domains, though im not sure how to go about doing that.

To my limited knowledge, you can avoid loading the assemblies by querying them beforehand using the Assembly class.
A full working model would look like this:
1 - Collect information through the Assembly class
Assembly File:
Assembly assembly = Assembly.ReflectionOnlyLoadFrom(fileName);
Local assembly:
Assembly myAssembly = Assembly.GetExecutingAssembly();
2 - Iterate through the classes present on each Assembly reference
Assembly mscorlib = typeof(string).Assembly;
foreach (Type type in mscorlib.GetTypes())
{
Console.WriteLine(type.FullName);
}
3 - After choosing which assembly to use, Load it into your Application Domain
Assembly assembly = Assembly.Load(fullAssemblyName);
or
Assembly assembly = Assembly.LoadFrom(fileName);
Examples copied from the following post, so feel free to upvote the responses there if you feel they contributed to solve your issue!
C#: List All Classes in Assembly

Related

Proper dependency loading for plug-ins using Assembly.Load, Assembly.LoadFile

I am working on a plug-in based framework that allows plug-ins to exchange data between one another based on some contract (interface).
Currently, a Windows Service can load the plug-ins in two ways:
In the same AppDomain as the Windows Service hosting the plug-ins
In another process that the Windows service communicates with via named pipes (WCF).
This works nicely most of the time. However, there are certain scenarios where one plug-in might reference an assembly, and another plug-in references a newer version of the assembly. In this scenario, I always want the newer version of the dependency to be loaded regardless of which plug-in is loaded first.
Here is the folder structure:
Windows Service Directory (AppDomainBase)
Plugins
Plugin1
Plugin1.dll
SharedDependency.dll (1.0.0.0)
Plugin2
Plugin2.dll
SharedDependency.dll (1.0.1.0)
I have done a lot of research already, and tried many different things. That said:
I cannot redirect assembly bindings via an app.config file. Although this works, it is not practical because I do not know all of the dependencies ahead of time and cannot add every single one to the app.config.
I can't use the GAC
I don't want multiple versions of the same assembly loaded, just the newest one.
I have read about Assembly.Load, LoadFrom, and LoadFile and have tried using all of them. I am still not 100% clear on the difference between Load and LoadFrom. They both seem to automatically load each plug-in's dependencies through fusion and probing from the directory where they are loaded.
My current solution is to search all sub-directories of the AppDomainBase to find and cache all of the DLLs in each plug-in's folder. If I encounter the same assembly more than once, I always keep track of the newest version and its location.
Then, I load each plug-in by calling Assembly.LoadFile so that no dependencies are loaded by fusion. I am subscribing to the AppDomain.CurrentDomain.AssemblyResolve event. When that event is raised, I inspect the Name of the assembly to determine which assembly should be loaded that was pre-cached, and then I load it by calling Assembly.Load.
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
try
{
Log(string.Format("Resolving: {0}", args.Name));
// Determine if the assembly is already loaded in the AppDomain. Only the name of the assembly is compared here.
var asm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().FullName.Split(',')[0] == args.Name.Split(',')[0]);
if (asm == null)
{
// The requsted assembly is not loaded in the current AppDomain
Log(string.Format("Assembly is not loaded in AppDomain: [{0}]", args.Name));
// Determine if the assembly is one that has already been found and cached
var asmName = _RefCandidates.Find(a => a.Name.FullName.Split(',')[0] == args.Name.Split(',')[0]);
if (asmName != null)
{
// The assembly exists in the cache, but has not been loaded. Load it.
Log(string.Format("Pre-loaded assembly found in cache. Loading: [{0}], [{1}]", asmName.Name, asmName.Name.CodeBase));
return Assembly.LoadFile(asmName.File.FullName);
}
}
else
Log(string.Format("Assembly is already loaded in AppDomain: [{0}], [{1}]", asm.GetName(), asm.GetName().CodeBase));
return asm;
}
catch (Exception ex)
{
Logger.Write(ex, LogEntryType.Error);
return null;
}
}
First of all, what is the best way to accomplish what I need to do, and what am I doing wrong?
Second, what happens if a dependency in the chain is expecting to reference something that is in the GAC? I assume it will no longer be found since I am using LoadFile and skipping fusion all together. Also, I have read some things about serialization not working with LoadFile. What specifically? How about resource assemblies?
This model is assuming that all newer versions of dependent assemblies are backward compatible since I'll be loading only the newest version.
Any input is greatly appreciated.
You can't load assembly manually, if the resolution of this assembly not fails(only in this case AssemblyResolve is raised).
So, your plugin architecture can not be implemented with Assembly.Load* methods.
There are two paths now.
First(not recommended): somehow remove the restriction(for example use Assembly.Load at start, and in any point you need an object, search for CurrentDomain assemblies, pick right assembly and by reflection construct objects and use them).
Second(recommended): review your initial problem and search for solution, that can be simple to implement and maintain.
Take a look, what Managed Extensibility Framework offers for plugin architecture.
SharpDevelop folks wrote a book, telling us about their plugins tree.
Find your way.
Also see this link about assembly loading context to understand why Assembly.Load without AssemblyResolve event will not work.

Could not load type from assembly

Before you say anything, I have read the previously asked questions about this issue. The answers there did not fix my problem.
It's pretty simple, I guess, if you know the answer. Here's my problem:
I've got a solution with several projects, I'm creating a plugin-based application where I use Reflection to load all assemblies. This part goes fine, I load all my assemblies like so
var filePaths = Directory.GetFiles(#"C:\CustomerServiceModule\", "*.dll", SearchOption.AllDirectories).Where(n => n.Contains("bin"));
foreach (var f in filePaths)
{
Assembly.LoadFile(f);
}
Now I want to create an instance of a type, so I can work with it:
var assembly = AppDomain.CurrentDomain.GetAssemblies().Where(a => a.ManifestModule.Name == "Kayako.dll").SingleOrDefault();
var name = assembly.GetTypes();
var type = assembly.GetType("Kayako.KayakoData");
var lol = Activator.CreateInstance(type);
This goes badly because inside KayakoData I have this:
KayakoService _service = new KayakoService("xxx", "yyy", "zzz");
This service is an assembly that works, I've used it before. Version number is fine, there's nothing in the GAC that overrides it, I can't see any errors using Assembly Binding Log Viewer. I still get this error:
[System.LoadTypeException]{"Could not load type 'KayakoRestAPI.KayakoService' from assembly 'KayakoRestAPI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.":"KayakoRestAPI.KayakoService"}
Anyone have any bright ideas? I've been staring myself blind at this. If I remove the service part from KayakoData the whole thing works, but I really need to run the service.
Quote from the documentation of the LoadFile method:
Use the LoadFile method to load and examine assemblies that have the
same identity, but are located in different paths. LoadFile does not
load files into the LoadFrom context, and does not resolve
dependencies using the load path, as the LoadFrom method does.
LoadFile is useful in this limited scenario because LoadFrom cannot be
used to load assemblies that have the same identities but different
paths; it will load only the first such assembly.
Conclusion: try LoadFrom in order to load dependent assemblies as well.
You just need to change the version of .dll from assembly info of that project. Then rebuild your solution.

Can't obtain an instance of Type class for a type not defined in the currently executing assembly

How do I obtain an instance of a Type class for a type not defined in the currently executing assembly or in mscorlib.dll?
a) Namely, I've defined a class type someType in assembly CSharpSnapIn.dll, located at E:\CSharpSnapIn.dll, but for some reason when I try to specify an absolute path to this assembly, I get an exception:
Type t = Type.GetType("someType, E:\\CSharpSnapIn.dll"); // exeception
b) I've also tried by putting CSharpSnapIn.dll into \bin\debug directory of a currently running application, but I still get an exception:
Type t = Type.GetType("someType, CSharpSnapIn.dll"); // exeception
thanx
EDIT:
1) I've declared another class type someType2 ( inside CsharpSnapIn.dll )and this time it worked:
Type.GetType("someType2, CSharpSnapIn");
Difference between someType and someType2 is that someType implements an interface declared in external assembly asmIn, but this shouldn't cause an exception, since CsharpSnapIn.dll does have a reference to asmIn?!
2)
Note that the assembly doesn't need to
be loaded first, so long as the
assembly resolver can find it
In other words, calling Type.GetType() first loads an assembly and then creates a Type instance?
3)
The assembly has to be found by
probing, so it would have to be in the
bin directory as per your second
example. If it's an assembly with a
strong name, you have to give all the
details.
So you're saying we can't specify an absolute path ( to an assembly ) using Type.GetType(), but instead assembly needs to reside inside a bin directory?
You will need to first load the assembly:
Type t = Assembly
.LoadFrom(#"e:\CSharpSnapIn.dll")
.GetType("SomeNs.SomeType", true);
You need to give the assembly name - not the file which contains it.
For example:
Type t = Type.GetType("someType, CSharpSnapIn");
The assembly has to be found by probing, so it would have to be in the bin directory as per your second example. If it's an assembly with a strong name, you have to give all the details. Note that someType here also has to be fully qualified in terms of the namespace.
Note that the assembly doesn't need to be loaded first, so long as the assembly resolver can find it. For example, if the assembly is in the same directory as the currently executing assembly, that will be fine in most cases.
As Darin says, an alternative is to load the assembly directly - although in my experience there are quite a few "gotchas" in loading assemblies explicitly, particularly if you've got two assemblies in different locations which both rely on a third assembly. Making sure you only get that third assembly loaded once can be tricky.
You need to choose between LoadFile and LoadFrom etc. Here are some remarks from MSDN:
Use the LoadFile method to load and
examine assemblies that have the same
identity, but are located in different
paths. LoadFile does not load files
into the LoadFrom context, and does
not resolve dependencies using the
load path, as the LoadFrom method
does. LoadFile is useful in this
limited scenario because LoadFrom
cannot be used to load assemblies that
have the same identities but different
paths; it will load only the first
such assembly.

Assembly.ReflectionOnlyLoadFrom not working

I have an Assembly Library1.dll which contains some Interfaces, which were serialized as a byte array into the database. For some reasons we have to change the Interface properties and defintion. so now i am writing a migration utility. So i have 2 versions of Library1.dll , In my utility i have created a folder where i store the new version of Library1.dll . This utility in turn also references Library1.dll hence in bin folder contains Library1.dll but this dll is compiled on older version. My new version of Library1.dll is stored in a private path which i am passing to Assembly.ReflectionOnlyLoadFrom function to instantiate and hence GetTypes on the assembly loaded which further would enable me to do conversion of data.
But I always get ReflectionTypeLoadException when trying to load Library1.dll from private path.
Please help guys!!!. any help would be appreciated. I am really stuck.
Thanks,
AG
If your Library is referencing another dll, GetTypes will fail when it hits a type that uses an external type. Unlike normal assembly loading, ReflectionOnly Assembly loading will not resolve dependencies. You can either subscribe to AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve and load the dependencies as required, or you could pre-load them.
This is the code I use for this:
var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
foreach (var assemblyName in assembly.GetReferencedAssemblies()) {
try {
Assembly.ReflectionOnlyLoad(assemblyName.FullName);
} catch {
Assembly.ReflectionOnlyLoadFrom(Path.Combine(Path.GetDirectoryName(assemblyPath), assemblyName.Name + ".dll"));
}
}
This will try to load all dependencies of the reflection-only loaded assembly first by fullname, then by path (assuming that the dependency is in the same directory as the loaded assembly).

How to load only signed assembly to a new AppDomain?

I'm doing a addin system where the main app loads assemblies Addin1.dll and Addin2.dll on runtime in new AppDomain's.
However, in case that Addin1.dll is signed (strong name) with my key and Addin2.dll is not, I want to be able to only load Addin1.dll and reject Addin2.dll.
I'm suspecting that it needs to be done by setting some parameters in AppDomainSetup?
Look into the Assembly.Load method that takes an Evidence parameter. You can find an example of how to create an evidence from your public key here.
You can implment a DomainManager and base your load/block decision's on whatever you like. I answered a somewhat related question here.
You can use Load method of AppDomain class to load new assembly into Appdomain, provided the assembly's publisher policy is satisfied by the client or end user environment.
Also the strong named assembly follows all the rules laid down by publisher of the assembly and the CLR. So the user of the assembly needs to satisfy the security aspect of the assembly being loaded into the appdomain.
The CLR loads the referenced global assembly from the GAC using the strong name properties. If the referenced assembly is available in the GAC, CLR will return its containing subdirectory and the file holding the manifest is loaded. Finding the assembly this way assures the caller that the assembly loaded at runtime came from the same publisher that built the assembly the code was compiled against. Now comparison of public key token in the referencing assembly’s assemblyRef table and public key token in the referenced assembly’s AssemblyDef table. If the referenced assembly isn’t in the GAC, the CLR looks in the application’s base directory and then in the private paths identified in the application’s configuration file; if the application containing the assembly is installed using the MSI, then CLR invokes MSI to load the required assembly. IF the assembly is not found in any of these location, an exception is thrown and finally the binding of assembly fails.

Categories