Should I rely on dynamically loaded assemblies? - c#

I have the following situation.
Assembly D contains class Data.
Assembly F1 contains class, which creates, fills and returns Data.
Assembly F2 contains class, which accepts Data as input.
The trick is, that all of these assemblies are plugins and are loaded dynamically. Of course both F1 and F2 references D, but in the runtime all three are loaded by host application.
Now what happens if someone replaces D binary file with newer version, which has a different interface?
I wrote a test application, which did something like that, with the following results:
Adding new field in class Data causes no exception;
Replacing the existing field with another one results in TargetInvocationException with information, that requested field does not exist
If .NET keeps track of the interface calls, I'm fine. That's because accessing the unchanged part of library will simply work and if that part changes, I'll get an exception simply telling me that. So it will either work (on the interface level) or not - no undefined behavior.
My questions:
How are the types resolved in the runtime - especially in case of non-matching assembly versions? Does .NET keep track of field/property/parameter/return value types and names?
Is there a way to force the referenced assembly to be required in some specific version?

Your second question: In Visual Studio there is a easy way to force your application to use a specific version of a referenced assembly. Simply click on the assembly under references and look at the properties. There is a property called "Specific version". If you set it to true and load another at run time, you will get an exception.
Your first question: I don't know exactly how .Net determines, when it is able to use an assembly, that it was not compiled with. So if the signature of a class/interface changes, .Net will throw an exception. I think .Net simply tries to use the new assembly and throws an exception if the methods/properties in the class/interface in the new assembly has a modified signature.

Related

How to find a type that is not loaded yet in AppDomain?

I'm developing modular application using WPF and Prism.
All my UserControls have separate assemblies and implement IUserControl interface.
I would like to list all Types which implement IUserControl interface form a loaded module library in this way;
//ModuleA.cs
var interfaceType = typeof(IUserControl);
var userControlTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => interfaceType.IsAssignableFrom(p) && p.IsClass);
But I cannot see all UserControl types implementing IUserControl in userControlTypes list.
When I use the all classes that implements IUserControl in Bootstrapper.cs like in the following;
var userControlTypes = new List<Type>()
{
{typeof(HastaKayitControl)},
{typeof(ViziteUserControl)},
{typeof(DenemeUserControl)},
...
};
I can get all desired UserControls from the list just I wrote above(userControlTypes).
What is the reason behind this?
FYI:
All assemblies target the same .NET framework version.
My Prism version is 6.1.0
I will use userControlTypes to show all UserControl types inside the application to the end-user.
IUserControl interface contains nothing.
This behavior is by design. The .net CLR will not load in an assembly unless it is called/entered which forces it to be loaded. Imagine the startup cost of running an app if every .dll file in the directory were loaded into memory when the application started as opposed to when a type was referenced at run time for the first time, some apps with large libraries would have load times of minutes (maybe even more?). Also it would not be realistic because some types are resolved to libraries outside of the execution folder like assemblies that resolve to the GAC.
In your first example AppDomain.CurrentDomain.GetAssemblies will only return the loaded assemblies, not all the assemblies, in that application domain. To see this you could add a {typeof(ViziteUserControl)} (taken from your next code part) and place it right above it, this will force the type (and containing assembly) to be loaded by the CLR and now it (types containing assembly) too will be returned by AppDomain.CurrentDomain.GetAssemblies.
In your next code fragment your code is explicitly entering these assemblies and adding the types. I do not think this requires any explaining.
So if you want AppDomain.CurrentDomain.GetAssemblies to load all your types across your application you need to force the assembly to load into memory if it has not already done so. Depending on your structure you could do this a couple of ways.
Iterate through the .dll files on disk (using a reference location like Assembly.GetExecutingAssembly.Location) and call Assembly.LoadFrom. Use wild cards to ensure you are only loading your assemblies and not every .dll library you are encountering.
Reference interested types in a configuration file and load them from there. You can use Type t = Type.GetType(yourConfigType); when creating your list of types from your configuration string list.
Reference interested assemblies in a configuration file and load in the DLL in the same manner as option 1.
Just hard code the list as you did in your last example.
If you choose option 1 or 3 you will have to check to make sure you have not already loaded the assembly in memory before you call Assembly.LoadFrom. You can do this by again checking what is already loaded with AppDomain.CurrentDomain.GetAssemblies().Any(x =>your search query).
Also Note that once you load an assembly into your application domain you cannot unload it for the life of that application domain. If you do not want this but you still want to dynamically find all your types you will have to create a 2nd application domain to find all the types and return them as an array/list of fully qualified type name as a string. You can then unload this created application domain. Also, as correctly noted by #Peter below in the comments, use ReflectionOnlyLoadFrom if you go with this approach. This incurs much less overhead.
AppDomain.GetAssemblies() tells you the loaded assemblies, not the referenced ones. I can't speak to the Prism aspect of your question, and I agree with the comments that there is probably a better way to design this. But…
If you really want to enumerate all of the types that might get loaded in your AppDomain, you can approximate this by enumerating the types in the existing assemblies (i.e. as you've done here, with AppDomain.CurrentDomain.GetAssemblies(), but then for each assembly, call GetReferencedAssemblies()), which returns an array of AssemblyName values that you can use to load additional assemblies. For each of those, you can in turn inspect all of their types (to find the implementors of IUserControl) and to call GetReferencedAssemblies() to continue the recursive search.
Note that this still will not necessarily return all implementors of the IUserControl interface that your process might load. Assemblies can be loaded by means other than being referenced in your AppDomain's assemblies, such as by code searching a directory for candidates, or even the user explicitly naming an assembly to load. This is why using mechanisms directly supported by whatever API you're using is a much better approach, to make sure that you find exactly those assemblies that that API would find.

C# Cannot be used across assembly boundaries because it has a generic type parameters that is an embedded interop type

I am facing this error with C# (wpf).
This link has not been useful
Cannot be used across assembly boundaries because it has a generic type parameters that is an embedded interop type
Just to explain the structure of my program I can tell that:
I am using a library made by an external company. We can call it PCDLRN
In the solution I have a project made by me which incluse the types in the previous lib. In my library I define:
public ObservableCollection<PCDLRN.DimensionCmd> obcPcdlrnDimensionCommands = new ObservableCollection<PCDLRN.DimensionCmd>();
in order to by used in my main program.
So in short:
PCDLRN->MYLIB obcPcdlrnDimensionCommands --> MY PROGRAM myPcd.obcPcdlrnDimensionCommands
in my program I want to access the aforementioned ObservableCollection but it doesn't build giving the error in the title.
--EDIT---
As suggested I have changed from embedded = true to false by changing the prop as in picture but the error remains
As WasGoodDone remarked, you need to use the same class for both (all) assemblies you use for generics.
In other words, if you have assembly1, that references some interopAssembly, and assembly2, that references the same interopAssembly, and you switch embedded interop type to true, then you will have two copies of types from interopAssembly.
If you want to use some cross-references from assembly1 to assembly2, .NET can't resolve it, because from their point of view, the classes are different.
When you switch the embedded option off, your assembly will reference the other assembly which contains the interop types. And in this way you can use the interop types in different libraries.
So, if you have the problem described above, it means that you have at least two assemblies referencing PCDLRN, and you must switch off embedded interop type in all of them.
Embed Interop types was not shown on the property pages for my assembly (as in the question above), so I edited the project files directly to fix this problem:

How does Assembly.Load(byte[]) work?

I was just wondering what happens if I was to load the same assembly bytes twice within a web app.
For example I have this code
byte[] assem = System.IO.File.ReadAllBytes(appRoot + "/Plugins/Plugin.dll");
var loadedAssem = Assembly.Load(assem);
var plugin = loadedAssem.CreateInstance("Plugin.ThePlugin") as IPlugin;
I ran this code and on the first request I assume it would load the assembly into ram ( or the http runtime appdomain? ) and then I can create instances of whatever is in there.
If I ran this code again, say on the second request what would happen to the assembly on the first request?
Would is still exist in ram? if so how does it differentiate between the two assemblies? or does it overwrite the previously declare classes?
This is for my understanding, as like I do in PHP its not just a case of "require_once".
This will load two distinct copies of the assembly, each of which can be used from your application. The types in each assembly are distinct types and will not inter-operate with one-another. For instance, if you take a Widget from Copy1 and try to pass it to a method that takes a Widget on Copy2, this will cause a runtime failure. It is not possible to unload assemblies once they have been loaded in this way (i.e. into your main AppDomain.)
Regarding instantiation:
If you use Assembly.CreateInstance (as shown in your post), this will create it from the Assembly instance you used to make the call.
If you use an Activator.CreateInstance that takes a string, you need to specify the assembly name. Since both loaded assemblies will have the same name in this case, it will use assembly resolution rules, which, I think by default, will favor the first match (so the assembly you loaded first.) I'm not certain of this. You can hook the AppDomain.AssemblyResolve event to provide your own prioritization and make it use your most-recently-loaded assembly.

Dynamic loading of DLL

I have a program which needs to use a large number of plugins.
Each plugin must support a very basic interface, this interface is defined in a DLL (IBaseComponent for simplicity of question sake).
Each plugin will be in a specific directory (AppDirectory\plugin\plugin-type).
Each plugin can have any name for the plugin's dll (AppDirectory\plugin\plugin-type\plugin-name.dll).
So I need to check through each plugin subdirectory, find each plugin that has a class which supports the IBaseComponent interface, instantiate the class and call some functions on the plug in.
ok, all fine and dandy, none of this is particularly hard. The problem though is that I seem to be running into some weird issues.
Every plugin needs to have the Base.dll file in the individual plugin folders (instead of just in the program that will be loading the plugin) and also it seems that I get many errors and warnings around dynamically loading a dll which have dll's that also need to be loaded.
I'm using:
pluginModule = System.Reflection.Assembly.ReflectionOnlyLoadFrom(PathToAssembly);
in order to grab the plugin dll and using:
types = moduleAssembly.GetTypes();
in order to grab the types contained within the dll.
I am iterating over the types and checking if the individual type is of the IBaseComponent interface (signifying this is a valid to load class) with:
if (type.GetInterface("FrameworkNameSpace.IBaseComponent") != null)
//it's of the IBaseComponent interface
Later, in order to actually create an instance of the class from the dll I use:
pluginModule = System.Reflection.Assembly.LoadFrom(PathToAssembly);
and then use:
types = component.GetTypes();
In order to get the types within the module then select and load the class which supports the interface same as above.
The problem seems to be on when I use:
types = component.GetTypes();
When actually trying to load the class, Instead of simply looking at it. (Hence my different usage of LoadFrom and ReflectionOnlyLoad)
The Exception I receive on the GetTypes call (on a second plug in, but never the first!) is:
{"Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information."}
With the LoaderExceptions property as:
{"The specified module could not be found. (Exception from HRESULT: 0x8007007E)":null}
I'm unsure why this occurs. The DLL is in the plugin folder, and the DLL containing the IBaseComponent interface is also in every one of the plugin directories. Am I going about this the wrong way?
Also is it required for me to keep a copy of the DLL containing IBaseComponent within each plugin subdirectory as well as the one used by the program itself, or am I doing something incorrectly that would allow me to remove this requirement?
I am aware of MEF which is what I wanted to use but unfortunately because I am required to support this on .net 2.0 I am unable to use MEF.
This is a LoadLibrary() failure. Sounds to me that you plugins have a dependency on some unmanaged DLLs. Yes, Windows is going to have a hard time finding these DLLs, it has no reason to look in the plugin directories. Maybe it works the first time because your app's default directory happens to be set to the correct directory. Which would then also be the workaround, use Environment.CurrentDirectory.
Finding out exactly which dependencies can not be found is key. Unmanaged ones are not going to show up in fuslogvw.exe, you can dig it out of a trace from SysInternals' ProcMon utility.

How Do I Load an Assembly and All of its Dependencies at Runtime in C# for Reflection?

I'm writing a utility for myself, partly as an exercise in learning C# Reflection and partly because I actually want the resulting tool for my own use.
What I'm after is basically pointing the application at an assembly and choosing a given class from which to select properties that should be included in an exported HTML form as fields. That form will be then used in my ASP.NET MVC app as the beginning of a View.
As I'm using Subsonic objects for the applications where I want to use, this should be reasonable and I figured that, by wanting to include things like differing output HTML depending on data type, Reflection was the way to get this done.
What I'm looking for, however, seems to be elusive. I'm trying to take the DLL/EXE that's chosen through the OpenFileDialog as the starting point and load it:
String FilePath = Path.GetDirectoryName(FileName);
System.Reflection.Assembly o = System.Reflection.Assembly.LoadFile(FileName);
That works fine, but because Subsonic-generated objects actually are full of object types that are defined in Subsonic.dll, etc., those dependent objects aren't loaded. Enter:
AssemblyName[] ReferencedAssemblies = o.GetReferencedAssemblies();
That, too, contains exactly what I would expect it to. However, what I'm trying to figure out is how to load those assemblies so that my digging into my objects will work properly. I understand that if those assemblies were in the GAC or in the directory of the running executable, I could just load them by their name, but that isn't likely to be the case for this use case and it's my primary use case.
So, what it boils down to is how do I load a given assembly and all of its arbitrary assemblies starting with a filename and resulting in a completely Reflection-browsable tree of types, properties, methods, etc.
I know that tools like Reflector do this, I just can't find the syntax for getting at it.
Couple of options here:
Attach to AppDomain.AssemblyResolve and do another LoadFile based on the requested assembly.
Spin up another AppDomain with the directory as its base and load the assemblies in that AppDomain.
I'd highly recommend pursuing option 2, since that will likely be cleaner and allow you to unload all those assemblies after. Also, consider loading assemblies in the reflection-only context if you only need to reflect over them (see Assembly.ReflectionOnlyLoad).
I worked out Kent Boogaart's second option.
Essentially I had to:
1.) Implement the ResolveEventHandler in a separate class, inheriting from MarshalByRefObject and adding the Serializable attribute.
2.) Add the current ApplicationBase, essentially where the event handler's dll is, to the AppDomain PrivateBinPath.
You can find the code on github.

Categories

Resources