My project is an application in which we load various assemblies and perform operations on them.
We are stuck at a situation where we need to add a reference to the assembly we load (which will be selected by user). So I need to add a reference to the DLL at run time.
I tried this site but here they support only microsoft DLLs like System.Security etc. I want to add a reference to a user created dll (class library).
You can't "add a reference" at runtime - but you can load assemblies - Assembly.LoadFrom / Assembly.LoadFile etc. The problem is that you can't unload them unless you use AppDomains. Once you have an Assembly, you can use assemblyInstance.GetType(fullyQualifiedTypeName) to create instances via reflection (which you can then cast to known interfaces etc).
For a trivial example:
// just a random dll I have locally...
Assembly asm = Assembly.LoadFile(#"d:\protobuf-net.dll");
Type type = asm.GetType("ProtoBuf.ProtoContractAttribute");
object instance = Activator.CreateInstance(type);
At which point I can either cast instance to a known base-type/interface, or continue to use reflection to manipulate it.
If the assembly is in another location than the current or in the GAC, just use the
AppDomain.CurrentDomain.AssemblyResolve event to deliver the assembly yourself.
If you load an assembly at runtime, it will look for all its dependencies in the current location or the GAC, and load them if found, else error.
The Composite UI Application Block facilitates the design and implementation of your client applications in three areas:
It allows your application to be based on the concept of modules or plug-ins.
It allows developers with shell expertise to build components that hide user interface complexity from the business logic development.
It facilitates development using patterns for loose coupling between modules.
For WPF: Take a look at Prism: patterns & practices Composite Application Guidance for WPF and Silverlight site It does the assembly loading you require and actually uses Unity internally as it's IoC container.
For non WPF: Take a look at Smart Client - Composite UI Application Block
Or alternatively: Try any of the IoC containers like Castle Windsor, autofac, unity, etc.
Related
I'm developing an application that heavily relies on a plugin architecture (*).
However I'm not sure what design pattern to use for dependencies between plugins, e.g. when plugin A depends on plugin B, possibly with some constraints (plugin B version between v1.05 and v1.30 or so)
My thoughts so far:
I could specify an interface for plugin B that never changes, and have plugin A reference this interface project only. Plugin B is then free to implement this in whatever way with versioning, and the latest available implementation will just be dependency-injected into the requested interfaces.
This could work, but it seems as though defining an interface which is very much tailored to the specific plugin's functions is a bit unnecessary; plus I suppose that I'd have to stick to that interface then; I could only enhance the plugins implementation in future versions easily, but not the interface.
I could ignore interfaces and just develop the plugins' implentations. Plugin A's project could then directly reference Plugin B's .dll. But as far as I know, this would cause errors when replacing Plugin B's .dll with a newer version, unless I add explicit version redirects in my applications config, wouldn't it?!
Are there any best practices? I suppose this issue is very similar to Nuget packages' depdendencies - does anyone happen to know how they have solved it?
Thanks
(*) in case it matters, my plugin architecture works as follows: I have all my plugins implement an interface IPlugin.
My main app then scans the plugin directory for all .dlls, filters out all classes that implement IPlugin, and uses Ninject to add a binding from IPlugin to the specific implementation (in the end, there'll be several bindings available for IPlugin, e.g. IPlugin -> Plugin1, IPlugin -> Plugin2 etc.). I'm then using Ninject to request/create a singleton instance of each plugin and register it in my main app. That way, my plugins can "request" dependencies via constructor arguments and Ninject/DI takes care of providing those.
As far as I am aware, Nuget tracks library dependencies using the metadata stored in the nuget package file. If I were you I'd avoid implementing arbitrary restrictions. What if one of your plugin developers wants to create a shared support library of useful classes, for example?
To my mind, a plugin should be a black box of functionality. If a plugin needs another plugin, then they should communicate via a standardized messaging platform rather than directly.
That said, you could always scrape all interface implementations from the library you load and hook those up as well as your plugins. That way the plugin developer can "request" implementations of those interfaces as well as plugins.
You'll need to cope with massive class libraries (I recommend only hooking up in Ninject interfaces that are referenced in plugin constructors) and with potential conflicts (two plugins might expect separate implementations of the same interface - which is the main reason I believe that a plugin should take care of itself internally, rather than hoping its design time expectations are fulfilled by the external plugin manager).
And in answer to (2), as long as the methods and properties you reference don't change name or signature, you shouldn't have any problems using a newer version of DLL B with DLL A. If you change a return type, change from a public field (which shouldn't exist in the first place) to a public property, change the parameters on a method or anything of that nature on a class that you're using from DLL B in DLL A, a recompile of A would be required.
I'm beating my head against the wall trying to find a container that will accomplish this.
What I'd like to do is have a AS.NET website running and not unload / recycle the AppDomain when I deploy a new or updated business rule contained in an assembly. This implies that the folder is outside of the bin folder, and preferably above it, not under it (although I can live with that). The closet I've come to this so far is using Autofac and MEF, but it seems like there's no way to unload a previously loaded assembly.
Anybody have any resources they can point me to?
Thank you,
Stephen
No, there is not. Because it is not possible to unload an assembly, only a total appdomain. THis is a .NET runtime limitation - and as every .NET IOC container has to live in the .NET runtime it can not bypass it.
If your imports are big enough isolating them in separate appdomains may be a good and viable idea.
You can not unload assemblies in .Net without unload whole AppDomain. So the only way to allow it is to load new assemblies into new AppDomains.
While it may be possible to build such IoC container that will marshal all requests to new AppDomains for many interfaces such code would put very significant restrictions on methods/objects exposed by the interfaces. Also many .Net objects can't cross AppDomain boundary (xml, UI/controls, HTML context, database related classes).
It is significantly easier to allow ASP.Net to deal with reloading of the AppDomain.
I'm currently working on a C# product that will use a plugin type system. This isn't anything new and I have seen much info around about how to use a interface to implement this functionality quite easily.
I've also seen methods to implement backwards compatibility by updating the interface name, e.g.: Interface change between versions - how to manage?
There are multiple scenarios which I can foresee with our product in regards to version mismatches between the main exe and the plugin.
Main Program same plugin version as plugin
Main Program newer than plugin
Main Program older than plugin
From the info I've been able to gather 1 & 2 work just fine. But I haven't been able to figure out how to correctly implement "forward" compatibility (3) properly.
It is our intention to only ADD methods to the plugin API.
Any ideas would be a great help.
Isolated PluginAPI DLL
First, Your PluginAPI (containing the interfaces) should be a separate DLL to your main application. Your main application will reference the PluginAPI, and each plugin will reference the PluginAPI. You're most likely already doing this.
Interface Versioning
Second, structurally, you should create a new interface each time you add a new property or method.
For example:
Version 1: Plugins.IPerson
Version 2: Plugins.V2.IPerson : Plugins.IPerson
Version 3: Plugins.V3.IPerson : Plugins.V2.IPerson
In rare cases where you decide to remove or completely redesign your API, example:
Version 4: Plugins.V4.IPerson //Without any Interface inheritance
Isolated PluginAPI DLL Versioning
Finally, I am not 100% sure how versioning of the PluginAPI .dll will go even with this structural architecture of Interface versioning. It may work
OR
You may need to have matching dlls for each version (each referencing the previous version(s)). We will assume that this is the case.
Solution for case 3
So let's now take your case [3], main program older than plugin:
Person Plugin implements Plugins.V2.IPlugin and references the V3 .dll (just to make it interesting).
Main Program references the V1 .dll
The plugin folder will contain the V2 and V3 plugin .dlls
The main app folder will only contain the V1 plugin .dll (among other files)
Main App will find and load the Person plugin and reference through a V1 definition for the IPerson interface
Of course, only V1 methods and properties will be accessible from the plugin to the Main App
(Additional methods will be accessible through reflection - not that you would want to)
Bonus Update
When you might use plugins
Third-parties extending your system. Source code would be better if that's an option, or if it's web-based, redirect to their URL. This is a dream for many software projects, but you should wait until you have an interested third-party partner before doing the extra work to build the plugin framework.
User Editable "Scripts". You should not build your own scripting language, instead you should compiled the user c# code against a restrictive interface in an appdomain that is very restrictive (disabling reflection and others).
Security grouping - Your core software might use trusted platform calls. Riskier modules can be separated into another library and optionally excluded by end-users.
When not to use Plugins
I am an advocate for less-is-more. Don't overengineer. If you are building modular software that's great, use classes and namespaces (don't get carried away with interfaces). "Modular" means you are striving to adhere to SOLID principles, but that doesn't mean you need Plugin architecture. Even inversion of control is overkill in many situations.
If you plan to open to third-parties in the future, don't make it a plugin architecture to start with. You can build out a plugin framework later in stages: i) derive interfaces; ii) define your plugins with interfaces within the same project; iii) load your internal plugins with a plugin loader class; iv) finally, you can implement an external library loader. Each of these 4 steps leave you with a working system on their own and move you toward a finished plugin system.
Hot Swappable Plugins
When designing a plugin architecture, you may be interested to know that you can make plugins hot swappable:
Without Freeing Memory - Just keep loading the new plugin. This is usually fine, unless it's maybe for a server software which you expect i) to run for a very long time without restarting; AND ii) expect many plugin changes and upgrades during that time. When you load a plugin at runtime, it loads the assembly into memory and cannot be unloaded. See [2] for why.
With Freeing Memory - You can unload an AppDomain. An AppDomain runs in the same process but are reference isolated - you can't reference or call objects directly. Instead calls must be marshalled and data must be serialised in between appdomains. The added complexity is not worth it if you're not going to change plugins often, there is: i) a performance penalty due to marshalling/serialization, ii) much more coding complexity (you can't simply use events and delegates and methods as normal), iii) this all leads to more bugs and makes it more difficult to debug.
So if option [2] entices you, please try [1] first, and use that architecture until you have the problems necessary for [2]. Never over-architect. Trust me, I have built a [2] architecture before during University, it's fun, but in most cases overkill and will likely kill your project (spending too much time on non-business functions).
You need to assume that your plugins only implement the interface(s) exposed. If you release a new version of your main program with new interface you will check to see if your plugins support that interface. Therefore if a new plugin is presented to an old version of main. It will either support the requested interface or will not and will fail the test as a valid plugin.
I need to implement a plugin architecture within c#/.net in order to load
custom user defined actions
data type handling code for a custom data grid / conversion / ...
from non-static linked assembly files.
Because the application has to handle many custom user defined actions, Iam in need for unloading them once executed in order to reduce memory usage.
I found several good articles about plugin architectures, eg:
ExtensionManager
PluginArchitecture
...
but none of them gave me enough sausage for properly unloading an assembly.
As the program is to be distributed and the user defined actions are (as the name states) user defined: how to i prevent the assembly from executing malicious code (eg. closing my progra, deleting files)?
Are there any other pitfalls one of you has encountered?
Have you thought about using the Add-Ins and Extensiblity framework from MS?
http://msdn.microsoft.com/en-us/magazine/cc163476.aspx
Michael
One technique is to load the additional assemblies into a separate AppDomain. Unloading the AppDomain will unload the assemblies.
You can't unload a single assembly. You can only unload a group of assemblies by unloading the AppDomain they are a part of.
This is essentially how SQL CLR works, and ASP.NET -- by having a transient AppDomain for user-supplied assemblies.
What are some guidelines and best practices for when to create new application domains within an application?
Also, what are some common uses and examples of how multiple application domains are used whithin an application?
The most common scenario I've seen is to be able to provide extensibility with a different security model than the main program.
Loading a plugin in a separate AppDomain allows two things:
You can implement a more restricted security model
You can prevent the plugin from tearing down your application if it's buggy
Another nice use of AppDomains are to load and inspect an assembly. Doing this in a separate AppDomain allows you to glean information (or run code) from a separate assembly, then unload the entire assembly from your process's space. If you load the assembly directly, there is no way to unload it. This is also useful if you want to be able to, at runtime, "upgrade" a type to a new version (ie: load a remote assembly, and reload it later).
It is recommended to create new domain when you need to host 3-rd party components within your application that are unreliable or you do not trust them (like plug-ins) or you want to be able to unload them.
A typical example is for plugin-/addin-like cases. Not only does it allow you to unload the DLL if required, it also gives you better security control over what the plugin is allowed to do.
Also, if you create temporary assemblies (code generation) which you want to unload again, this is a good way to do it. (LCG only allows implementing single methods, if you want to implement a complete class you need to emit to a "real" assembly).