How to implement plugin architecture in .NET? - c#

I have an interface in my main library. There will be multiple different implementations of this interface, those implementation will be part of different libraries, possibly distributed as nuget packages.
As per the requirement, user should be able to use a particular implementation by adding its corresponding nuget.
Providing an analogy, lets suppose I have an interface, IPizzaProvider.
public interface IPizzaProvider
{
Pizza GetMePizza(customizationParameter);
}
There will be multiple different implementations of this distributed in different NuGet packages.
DominosPizzaProvider
PizzaHutPizzaProvider
XYZPizzaProvider blah blah
Thus, these are different plugins for my main library.
Use Case:
A user adds my main library in their application.
Next, users as per their choice adds a particular nuget package (plugin) in their application.
User provides customization parameters to my main library.
Now, my library should be able to get object of Pizza through the interface without worrying about the implementation.
This will not only will help me to have loose coupling/ abstract implementation through an interface but also facilitate separate release cadence for supporting additional providers in future. I don't have to release my existing main library.
Additionally, users can also implement my interface themselves and use it with my main library.
Problem statement: How to load those DLLs in my main library and instantiate the implementation class dynamically at runtime.
One possible solution is to .NET Reflection. But then I have to scan all individual DLLs and find the assembly which contains implementation.
List<Assembly> allAssemblies = new List<Assembly>();
string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
foreach (string dll in Directory.GetFiles(path, "*.dll", SearchOption.TopDirectoryOnly))
allAssemblies.Add(Assembly.LoadFile(dll));
List<Type> providers = allAssemblies
.SelectMany(x => x.GetTypes())
.Where(t => IPizzaProvider.IsAssignableFrom(t) && t.IsClass).ToList();
There might be hundreds of DLLs at runtime path of the application and scanning them all might cause performance hit.
Is there any other possible way to implement this plugin architecture in .NET?
Java uses SPI for similar problem statement and has ServiceLoader class to load different implementation. It involves META-INF folder etc.

Related

How to load third-party implementations at run-time

I'm making a .Net application to manage and install mods. The application itself shouldn't be able to install mods for any particular game but should be able to call 3rd-party extensions to do so.
Let's say my mod manager expects an implementation of the given interface:
interface IGameManager {
// Deploy a modding configuration to the targeted game
void Deploy();
// Remove all managed mods from the targeted game
void Purge();
// ...
}
And someone else, working on a different code base, implement IGameManager to manage a specific game:
class MinecraftManager: IGameManager {
// ...
}
Then this person compiles it, publishes it and everyone could simply feed this extension to the main mod manager so it can manage their mods for the targeted game.
But how? Is there a way for my application to safely load and use such third-party implementations at run-time? And how to facilitate the making of third-party extension (e.g. giving an interface to build on but more elegantly and maintenance-friendly)?
Edit 1: Invalid syntax in MinecraftManager signature
You are essentially trying to design a plugin system. There are many implementations that you could reuse but the general idea is that:
You need your manager to be able to discover extensions. There are many ways to do that but the simplest and most used approach is to place extension assemblies under a well known directory in the file system. Then your manager can enumerate the assemblies in that folder by enumerating the files (or if you prefer that each extension has it own subfolder enumerate the subfolders)
Load the assembly. For that you will use one of the Assembly.Load.. methods. Since it is not possible to unload assemblies, you may want to first load the assembly for reflection only and once you decide that the assembly is valid you can load it in the ApplicationDomain in order to use it.
Use relfection to enumerate all classes of the assembly you just loaded and find the ones that implement the right interface (IGameManager). Altenatively you can require that extensions contains an "entry point" class of known name, then look for that class by name (using reflection).
Create an instance of the class(es) and use it (perhaps also keep it in a collection of loaded extensions)
Regarding the interface that extensions must implement: You should put the interface (and any other supporting interfaces) in a separate assembly. The assembly should contain only interfaces, no implementation. You can then publish the assembly. Once published the interface should never change.
If you need to add functionality you should create a new interface. This way old versions of the manager will work with newer versions of an extension (that is designed to implement the new functionality as well). Also your manager can determine which interfaces are implemented by an extension and act accordingly (thus maintaining compatibility). If the new functionality is mandatory, your manager should discard any extension that does not implement both interfaces.
I just found out dotNet 4 already have an extensibility framework (Documentations here), which is cleaner and safer than using Assembly.Load().
Here's the snippet I use to load my plugins from a given directory, if anyone encounter the same problem:
// Where T is the type you want to retrieve from the assemblies
private static IEnumerable<Lazy<T>> LoadExternalAssemblyFromPath<T>(string path, string pattern) {
CreateDirectoryIfDoesntExist(path);
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(path, pattern));
CompositionContainer container = new CompositionContainer(catalog);
return container.GetExports<T>();
}
// Usage:
LoadExternalAssemblyFromPath("C:/path/to/plugins", "*.dll");
Regarding the implementation of such plugin, Kouvarakis' solution on the matter is correct.

Modular application architecture and Castle Windsor

I'm developing a .Net desktop app that interacts with scientific instruments. There are a number of variations of this instrument, each with different features, components, etc, so I've come up with a plugin/modular architecture where a "module assembly" contains all of the necessary business logic, UI, etc. to interact with that hardware component/feature.
Currently I have one solution that contains everything - the "core" application project, common libraries, plus the "module" projects. The idea is that we install the whole lot to a customer site (rather than cherry-picking which DLLs they need), and "activate" the relevant modules using a config file that contains a list of required modules.
The main application project loads the modules using Castle Windsor, using an AssemblyFilter and a custom InstallerFactory. It searches each module assembly looking for a class implementing IWindsorInstaller and decorated with a particular custom attribute (which has a property containing the module name). The module's installer will only be run if the attribute's module name is one of those requested. These installer classes are responsible for registering everything needed by that module with Windsor (business logic, views, view models, etc.).
This solution works fine in my proof of concept, however I can see a scenario where two or more modules are functionally very similar, and will therefore need to share common code. Let's say I have projects "ModuleA" and "ModuleB", and their Windsor installers registers the same IFooService class in project "ClassLibraryX". The app will fall over because IFooService has been reigstered twice, and Windsor won't know which one to resolve when requested by a constructor.
What's the best way to handle this? Thoughts so far:-
Find out if a particular component has already been registered with Windsor. This feels hacky (if possible at all)
Register components using a name, but how do I request a named instance with constructor injection?
In each module project create a new interface, such as public interface IModuleAFooService : IFooService, and register/use this throughout the project (rather than IFooService).
Any thoughts?
Edit: in fact Windsor won't fall over when it tries to resolve IFooService. It will fall over when the second module attempts to register the same interface/concrete implementation!
The way I see it, you have a couple options. I think you have two main issues. The first is that you are installing the shared interface twice (or more than that). The second is that you could have two different versions of the shared interface.
For the first issue, I would separate out the shared interfaces into their own assembly. Inside that assembly, I would have an installer that is scoped to that assembly. Then, you can tell Windsor to install that shared component and it knows how to wire itself up.
For the second issue, you have two options (as I see it). First option is that you keep your shared components backwards compatible. Second option is to isolate you runtime (through app domains or processes).
Can you not provide some meta-data for the plugin, i.e give each plugin implementation a name attribute which can be used by windsor to identify which of the implementations you want?
I have not used Castle too much recently but I am sure it did have the notion of named Bindings/Registrations, so you could use that as a way to distinguish things, if that is not going to be possible and there is no other meta data you can think of using which would make it less ambiguous for Windsor, then I would just opt with your 3rd option.
Having just read your 2nd option again (after writing the above) that seems the best option, I cannot remember EXACT syntax but in most DI frameworks you do something like:
var instance = Get<IMyInterface>("Named This");
There will be loads of syntax examples on their documentation somewhere, but you will need to know the name on both the Windsor side to register it AND on the client side to request it.
Named instances are ok. You can define dependency on concrete named service via DependsOn(Dependency.OnComponent("paramName", "serviceName")) method in fluent configuration.

Interface for plugins to implement in .Net

I want to implement a plug-in system in my .net application, without the use of MEF.
My application loads and creates instances of types, that are contained in the DLLs.
There is an interface (IPluginContract) that the main application assembly uses to load dll types, and this very same interface is used by the dll projects (the plug-ins) to implement it.
So different projects need access to the same interface.
I can realize this requirement by pushing the interface class into a separate Class Library, that both main app and the plug-ins will reference.
Is it a correct way to work around the described problem?
Yes, pushing your interfaces out into a shared library is a preferred solution. You then only need to distribute this library to plugin developers, which could be considered as lightweight, but the plugin will be coupled to an exact version of the interface.
Another solution is a convention based solution, where plugin writers have types that "conform" to an interface e.g. have appropriate methods on a class which they can point to via a config file. You can then use reflection, IL generation, etc, to wire this up to a concrete internal interface\proxy. The benefit here is that plugins are then not hard-wired to a specific interface version, so there is more flexibility in versioning.
You could also consider versioning by maintaining all versions of your interface e.g. IPlugin_1, IPlugin_2, etc. It's then up to plugin writers to implement whichever version, and for you to be able to handle each version.
We have successfully taken two different approaches to this issue depending on the circumstances at the time (time to market, implementation difficulty, internals exposure concerns, etc):
1) Move the interface into its own DLL. This works well if the plugins don't need any other support objects/functions/data embedded in your main application DLL or if you don't want to expose public members in your main DLL to plugin writers.
2) Leave the interface in the main DLL. We have primarily used this when the refactoring cost to move the interface and associated classes was too high or when the plugins were completely self-contained (i.e. we author them for customers).

Interface Library Versioning - Breaking Changes

I currently have a C# project which uses plugins and has a fairly common approach to plugin handling: an IPlugin interface is stored in a dll which is linked in a tranditional dynamic way. The host app looks for class libraries exporting classes exposing this interface and loads them via reflection at run time.
The dll containing the interface also contains helper classes, for updating plugins, providing abstract base classes and so on.
My question is, what does it take to break the interface between my host and plugin assemblies? In other words, if I compile and distribute the host app and then distribute plugins that have been linked with a later version of the plugin dll (in which helper classes have changed, but IPlugin is defined in exactly the same way), will the host still pick up the plugins? How much of a change do I need to make to the plugin library before IPlugin is considered a different "type" by the reflection methods I am using?
If the assembly isn't loaded by a specific version than I would say the only breaking changes you will really encounter are when you change the interface contract. If you are just changing helper classes it shouldn't be a problem.

Plugin based application in C#

I have to make a graphical user interface application using the language of my choice. The application will run on Windows XP. It will be some sort of a complex windows form application.
I think and as per most suggestions, C# will be the best to use.
The tree structure on the left of the GUI will populate after reading from a configuration file which will be a binary file . (but initially I can work with a simple ASCII file to test my code.). The application will accept some inputs from the user through this GUI and will write the back to the same config file and will reflect the changes in the tree structure or the labels or any other pertaining field on the form.
There will be 3 tabs and 3 corresponding config files for each of the tabs.
I need some help designing the application for now. I am planning to make a host application (main application) and use the 3 tab controls as plugins. Is this workable ? If so can you please guide me on this. I mean how do I make 3 plugins in C# and how do I write the interfaces so that the main application knows which plugin to load and when to load it ? Will there be a separate “Plugin” folder under my project folder ? I hope you got my point though this is too little of an information for you to begin with.
Also there are some .cpp files already existing in the project. These files along with some .h files contain some important definitions and constants in them. These need to be integrated with my C# application. I have no clue how to do that but I am sure that it is possible by compiling the .cpp code in a .dll and then exposing the compiled .dll to my C# application. Please let me know if you need some more information for the top level design.
Thanks,
Viren
To implement a plugin interface manually, you will need a method something like this. I've left some TODOs in, where you would want to enhance the error handling and/or make the implementation a little more case specific.
public List<T> LoadPlugin<T>(string directory)
{
Type interfaceType = typeof(T);
List<T> implementations = new List<T>();
//TODO: perform checks to ensure type is valid
foreach (var file in System.IO.Directory.GetFiles(directory))
{
//TODO: add proper file handling here and limit files to check
//try/catch added in place of ensure files are not .dll
try
{
foreach (var type in System.Reflection.Assembly.LoadFile(file).GetTypes())
{
if (interfaceType.IsAssignableFrom(type) && interfaceType != type)
{
//found class that implements interface
//TODO: perform additional checks to ensure any
//requirements not specified in interface
//ex: ensure type is a class, check for default constructor, etc
T instance = (T)Activator.CreateInstance(type);
implementations.Add(instance);
}
}
}
catch { }
}
return implementations;
}
Example to call:
List<IPlugin> plugins = LoadPlugin<IPlugin>(path);
As for the c++ part of your question. There are few different ways you could approach this, though the correct choice depends on your specific situation. You can make a clr compliant .dll in c++, which your c# project could reference and call like any other .dll it references. Additionally, you could use P/Invoke to call into a native .dll.
One of the easiest plugin concepts I have ever used was certainly the Managed Extensibility Framework which will be part of .NET 4 (afaik). Unfortunately it is not yet finished and only a preview is available which may differ from the final version. That being said, we used MEF Preview 3 for a uni project and it worked without problems and it certainly made the whole plugin stuff a lot easier.
Look at the System.Addin namespace :
http://msdn.microsoft.com/en-us/library/system.addin.aspx
Otherwise you can do everything yourself. Before this namespace was available, I used a common interface "IPlugin" that every plugin/addin needed to use. I then had a loader which inspected all the *.dll in a folder then used reflection to check for the interface. I could then create instances of classes which implemented my plugin/addin interface
The cpp files will probably need converting to c#, or you could possibly create a dll to reference.
Take a look to Castle.
.NET Framework use COM model in its guts. See http://blog.caljacobson.com/2007/07/26/creating-a-plug-in-framework-in-c-resources/ for a list of plugin example using this techique.

Categories

Resources