Plugin registration without instantiating the plugin class - c#

I need to design a simple plugin framework for our application (.NET, WinForms 3.5).
The extension points will be several application events/scenarios that the user could "hook" into using a plugin, to perform a certain operation.
The way i would like this to work is:
Have a Plugins folder where users will place plugin DLLs (assemblies containing types derived from a specific base class/marked somehow).
Have my application plugin system locate these files and register them for later usage.
Invoke the right plugin at the right time (for example: OnException, OnLog, etc).
If i will create the plugin object (new it up) at registration, the DLL would be loaded into the process memory.
I am looking for an easy way to do the registration, and only "lazily" load the plugin assembly, when needed (IF needed at all).

You have a couple options for this - If you are able, you could require that each plugin provide a manifest or some other file that describes itself, and then you could examine all the manifests and load the appropriate plugin when necessary. This avoids examining the assembly, but it does require consistency between the manifest and the assembly, which can be tricky.
Otherwise, as you've indicated, examining the plugin assembly will load it into memory. The only way I've discovered to avoid this is to load them into a separate AppDomain, examine them and capture necessary information, then unload that AppDomain. There is an example of doing this for PRISM somewhere (I can try to track it down), but I'm not sure what framework you're using (MEF, MAF, PRISM, IoC, etc.).

An alternative to loading each candidate assembly in a new AppDomain, reflecting on it's types and finally unloading the AppDomain, you could try Mono.Cecil. You then will have to do something like this:
AssemblyDefinition ad = AssemblyDefinition.ReadAssembly(assemblyPath);
foreach (TypeDefinition td in ad.MainModule.GetTypes())
{
if (td.BaseType != null && td.BaseType.FullName == "MyNamespace.MyAddInBase")
{
return true;
}
}
Then you can load the right assemblies using Assembly.LoadForm and finally create instances of the add-ins using the Activator.CreateInstance overload that suits your needs.

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.

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

Using AppDomain in C# to dynamically load and unload dll

In one of my application, which is related to system diagnostics, the related DLL is to be loaded and unloaded dynamically in C#. After some search I found that a separate DLL cannot be loaded dynamically its the complete AppDomain. So I have to create an AppDomain and use that DLL to be loaded unloaded dynamically. But I could not find anywhere how can I use that in code. I can not show the app code since it is against company rules.
Can somebody tell me some application code to use it. I want to load and unload the dll dynamically using appdomain and call a specific method in that dll, the dll does not have any entry point.
Thanks for answers.
Ashutosh
How to: Load Assemblies into an Application Domain
public static void Main()
{
// Use the file name to load the assembly into the current
// application domain.
Assembly a = Assembly.Load("example");
// Get the type to use.
Type myType = a.GetType("Example");
// Get the method to call.
MethodInfo myMethod = myType.GetMethod("MethodA");
// Create an instance.
object obj = Activator.CreateInstance(myType);
// Execute the method.
myMethod.Invoke(obj, null);
}
As for how to unload it, you have to unload the AppDomain itself, see this
AppDomain Temporary = AppDomain.CreateDomain("Temporary");
try
{
Gateway Proxy =
(Gateway) Temporary.CreateInstanceAndUnwrap("Shim", "Shim.Gateway");
Match M = Proxy.LoadAndMatch("Plugin.dll",
"Though the tough cough and hiccough, plough them through");
}
finally
{
AppDomain.Unload(Temporary);
}
It's difficult to understand your question, but I will try to make some suggestions.
There is no reason you cannot dynamically Load a dll directly into your application w/o a separate App Domain, the trick is that you cannot unload it. This is only important if you may load multiple versions of the same dll (i.e. you want the ability to update this diagnostic component to a new version without halting the execution of your application). If that is what you are trying to do, then I suggest this CodeProject article.
Actually you can dynamically load assemblies into your app domain and run code from it, the issue is that you cannot then unload the assembly. You can however load additional app domains (and assemblies into them) and unload the app domain when you are done.
As its name suggests though, you then have a new application domain, and you can't just simply call its code and use its types you need to marshal your calls and data across the domain boundaries. If you search you will find lots of examples on how to do this.
Something to consider though, is that this is a common pattern, and there are ready made solutions for it, the framework itself has a whole addin namespace that is dedicated to this type of plug-in behavior, it might be worth your while in having a close look at that first. There is an article here that shows how to use it.
Thanks guys, here is link where i found answer to my quetion:
The MSDN forum description for load and unload of assemblies dynamically
The other dll can be dynamically loaded and unloaded using another class which does load assembly and and call methods in that assembly...
AppDomain.CreateInstanceAndUnwrap generally wants input as assemblies from current project or generally current namespace. to solve that i need Assembly.LoadFrom(); to be used in some other class and create AppDomain and create instance of this class using AppDomain object as given in link.
Thanks for ur replies guys.

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.

C# Controlling dll access

I have a program that utilises a plugin architecture. When the inital form loads, it scans the current directory, queries each dll and obtain some basic data which is displayed to the user.
Whilst using the program, the software will often need to ask the dll's to perform some work.
My question is, when the program initially checks the dll files, should I keep a reference to each dll object for future use, or should I query the dll files each time and create the object as and when needed?
if it's the first one, what is the best way to keep a list of an undetermined number of objects that derive from a common interface and then know which one to refer back to when needed?
Thanks.
Using the first one you could just create a
List<IYourCommonInterface> pluginDlls
and then just
pluginDlls.Add(dllReference);
Edit
Alternate method using a Dictionary, note that this will require you having some kind of ID for the dictionary that you can make use of to id the dlls.
Dictionary<SomeIDField, IYourCommonInterface> pluginDlls
pluginDlls.Add(dllRefrence);
Most apps do the check on load.
I wouldn't store the list of interfaces. If you do store them then you run into the possibility that the assemblies either disappear or are updated in some way. At which point you need to "refresh" them anyway.
Once you've loaded the assembly and gotten an instance of System.Reflection.Assembly for reflection (using Assembly.Load(), Assembly.LoadFrom(), Assembly.LoadFile(), etc.), the assembly is loaded. To quote MSDN on the subject:
...it is...possible to load specific assemblies into the current application domain
at runtime...There is no way to unload an individual assembly without unloading
all of the application domains that contain it. Even if the assembly goes out of
scope, the actual assembly file will remain loaded until all application domains
that contain it are unloaded. [emphasis mine]
So if you want to unload the DLLs until such time as you actually need them, you're going to have to create a new app domain and then unload that. Its easier to just load them and have done with it. You can keep the assemply reference around if you like, but if you call Assembly.Load() again, it won't actually load the assembly: it'll just get a reference to the previously loaded assembly.
If you've gone through the trouble of finding and loading the DLLs, normally you'll want to keep them around. This would depend mostly on how many resources the DLLs use and how your app is using the DLLs.
I'm assuming you're using LoadAssembly here. You can just store references to the assemblies you've loaded using some kind of map. Or even a list that you iterate through.
Perhaps if you give some more details we can help you better.

Categories

Resources