Passing a custom class as parameter to a loaded assembly - c#

I'm writing a clipboard/image uploading tool in C#, where a keycombo would e.g make a screenshot, then send the image to a plugin and then the plugin handles the uploading and returning of an URL.
Now, those plugins need to save settings, and those settings need to be editable inside my application, so I thought I'd use a data saving class I wrote a while ago, and pass a reference of an initialized instance of that class to the plugins.
The idea was to put that entire class into an include, which a plugin writer could just include in their project to handle the data, however despite both the plugin and main application using the exact same code, I get an error about the versions being different, namely this:
{"[A]CedInc.Persistence.XMLPersistenceDictionary.savenode cannot be
cast to [B]CedInc.Persistence.XMLPersistenceDictionary.savenode. Type
A originates from 'CloudBoard, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null' in the context 'Default' at location
'C:\git\CloudBoard\CloudBoard\bin\Debug\CloudBoard.exe'. Type B
originates from 'CloudBoard FTP upload plugin, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null' in the context 'LoadFrom' at
location
'C:\git\CloudBoard\CloudBoard\bin\Debug\plugins\CloudBoard FTP
upload plugin.dll'."}
My question is: Is it possible to pass an instance of a custom class to a plugin without having to put it in an assembly to be loaded by the plugin itself? and if so, how? Any idea/suggestion is welcome! I'm kinda stuck here.

While I would recommend a shared assembly version, you could alos supply your plugin authors a template code file with pre-defined class and method names. And then you could use reflection to search the loaded assembly to locate the classes and methods matching your predefined signatures. Once you find the methods, it is easy to Invoke them.

You expect plugins not to reference any of your code at all?
In this case you may be able to find some interface in Framework assemblies that works to be passed to plugin instead of class. Maybe IDictionary or IDictionary<string,string> would work. This way plugin will not need to reference any of your assemblies for serialization and you will be able to pass you custom implementation. As side benefit for plugin authors will be much more convinient to unit-test their plugins (with concrete class form a random library it is much harder).

Related

IsAssignableFrom returns false when type is loaded from embedded resource

I have an executable that I'd like to be able to share stand-alone, without having to make sure the dependent DLLs get copied. To achieve that, I've embedded the DLLs into the executable as resource files, using answers like this one. So far it's been going well and I'm able to access the interface - call it InterfaceA - in the DLL correctly. The application is also meant to load a 3rd party DLL, specified at runtime, which contains a class implementing InterfaceA. I use reflection to find a type implementing InterfaceA and use Activator.CreateInstance to create an instance.
The problem is that as I'm iterating over the available types in the 3rd party DLL, typeof(InterfaceA).IsAssignableFrom(thirdPartyType) always returns false. This is not the case, however, when my DLL is a regular reference and isn't embedded as a resource. It seems that just because the DLL is embedded as a resource, InterfaceA is treated as a different type. However, thirdPartyType.GetInterface(typeof(InterfaceA).FullName) always returns what seems to be the correct interface type.
How can I load the embedded DLL so InterfaceA isn't treated as a different type, or use it with the third party types so IsAssignableFrom and CreateInstance both work correctly?
I think the problem you are facing is assembly identity difference between having an assembly embedded and referenced.
Check versions. Are you sure third party assembly is built against the same version of assembly containing the InterfaceA which you load from resources?
EDIT: based on discussion in comments, the problem is potentially in the use of LoadFrom(). Using the LoadFile(string path), I was able to execute the scenario described in the question successfully.

.NET Application architecture allowing missing assembly

I am searching for the correct assembly setup and abstraction to get this issue solved:
I got an app using an assembly to access an external system. Now this assembly is not available on every computer as it must be installed before my application (it comes with the complete external system setup).
When I now start my app on a computer where this external system is not installed I get: "FileNotFoundException" (I've got an Application.ThreadException handler)
I would like to only "lously" reference that assembly and be able to run without it (do offer configuration, advice, simulation).
I guess I have to implement a wrapper but I am not sure where to start. Will the wrapper reference the real assembly or use reflection to call it when available?
I think you have already kind of answered your question. The best way to go about it is by implementing a "wrapper" that can take objects from this assembly and utilize the concrete objects of this assembly, then implement a stub that will take over when this assembly is not found.
This wrapper could be a proxy object if you implement the Proxy Pattern and it should be able to have some intelligent logic to switch to a different concrete object(s) when the above-mentioned assembly is not found. Since you are using c#.net it should be as simple as checking whether the assembly exists in a specific location without trapping the check logic within a try/catch block.
Edit
By the way, the wrapper cannot reference the assembly because the assembly is not included in your project...you are manually loading the assembly which is different. Then, in order to instantiate objects of this assembly and call methods of these objects you need to use reflection.
You could handle the AppDomain.AssemblyResolve event. It's called when an assembly cannot be found, and it gives your code the opportunity to track down the specified assembly and return it back to the app domain.

Dynamically loading assembly: why this code works?

In my situation there are three components: Consumer class, IExposedIface interface and Exposed class implementing IExposedIface. Both Consumer and Exposed are linked statically with IExposedIface, but Consumer bears no compile-time reference to Exposed.
I am trying to come up with a scheme which would allow Consumer loading different versions of Exposed at runtime (depending on input data - let's say each input document carries an information about which version of Exposed should be used to process it). To achieve this, I started studying AppDomains and now I have a basic version working.
So far it seems to me there are two options when it comes to providing IExposedIface assembly to Exposed assembly.
Having IExposedIface.dll only in Consumer's bin directory and handling AppDomain.AssemblyResolve event for the AppDomain in which I am creating an instance of Exposed
Having IExposedIface.dll both in Consumer's bin directory as well as aside each Exposed.dll.
Now consider that I build Exposed against this IExposedIface:
public interface IExposedIface
{
string SaySomething();
}
and I build Consumer against this IExposedIface:
public interface IExposedIface
{
string SaySomething();
string SaySomethingDifferent();
}
In the first case, the exception
Exception: Method 'SaySomethingDifferent' in type 'Exposed.Exposed' from
assembly 'Exposed, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
is thrown in the moment I call appDomain.CreateInstanceAndUnwrap(...) to create an instance of Exposed in the freshly created AppDomain.
That looks reasonable to me.
But in the second case, appDomain.CreateInstanceAndUnwrap(...) goes through just fine and I can without problems call 'SaySomething()' method on the retrieved object. An exception
The method 'SaySomethingDifferent' was not found on the interface/type 'IExposedIface.IExposedIface, IExposedIface, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null'.
is only thrown when I actually call SaySomethingDifferent() in Consumer.
I was quite surprised that in this second case CLR had let me go so far...Could someone explain why this is possible?
Case #1 means that Exposed.dll is binding against the wrong version of IExposedIface.dll - the metadata loader is able to detect this when loading the assemblies because it finds an unimplemented interface method.
Case #2 (probably) means that you have the correct version of each IExposedIface.dll besides each Exposed.dll so each assembly can load within its own AppDomain. However AppDomain A has a different interface than AppDomain B which is only a problem when the call actually crosses the AppDomain border.
I'd suggest not trying those binary compatibility games and rather do proper versioning (ie. create a new interface with the new methods, inheriting from the old interface, so the new version of IExposedIface.dll is really backwards compatible). Anything else is really hard to debug because you can accidently end up loading both versions of IExposedIface.dll if they are reachable for windows, and then you have two versions of a Type in the AppDomain causing no end of trouble ;)

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