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.
Related
How to version abstractions in .Net when applying Dependency Inversion in a high code-reuse environment
I am interested in shifting toward using Dependency Inversion in .Net, but have come across something that puzzles me.
I don’t believe it is tied to a particular method or provider of DIP, but more a fundamental issue that perhaps others have solved. The issue I'm solving for is best laid out step-by-step as scenario below.
Assumption / Restriction
A considerable assumption or restriction to put out there up front, is that my development team has stuck with a rule of keeping our deployed assemblies to one and only one Assembly Version, specifically version “1.0.0.0”.
Thus far, we have not supported having more than this one Assembly Version of any given assembly we’ve developed deployed on a server for the sake of simplicity. This may be limiting, and there may be many good reasons to move away from this, but never the less, it is currently a rule we work with. So with this practice in mind, continue below.
Scenario
You have an IDoStuff interface contained in an abstraction assembly
Stuff.Abstractions.dll with 2 methods.
You compile component A.dll
with a class explicitly implementing IDoStuff with 2 methods.
You move A.dll to production use, Assembly Version 1.0.0.0, Assembly File
version 1.0.0.0.
You move Interface.dll to prod, Assembly Version
1.0.0.0, Assembly File version 1.0.0.0.
Everything works fine. Time passes by.
You add another method (“DoMoreStuff” for example) to the IDoStuff interface so that a different Component B can call it.
(Keeping Interface Segregation OO principle in mind, let’s say the DoMoreStuff method makes sense to be in this relatively small IDoStuff interface.)
You now have IDoStuff with 3 methods in Stuff.Abstractions.dll, and you’ve built Component B to use the new 3rd method.
You move Stuff.Abstractions.dll to production use (upgrade it), Assembly Version 1.0.0.0, Assembly File Version 1.0.0.1.
(note that the file version is incremented, but the assembly version and therefore the strong name stays the same)
You move B.dll to production use, Assembly Version 1.0.0.0, Assembly File version 1.0.0.17.
You don’t do a thing to A.dll. You figure there are no changes needed at this time.
Now you call code that attempts to execute A.dll on the same production server where it had been working before. At runtime the Dependency Inversion framework resolves the IDoStuff interface to a class inside A.dll and tries to create it.
Problem is that class in A.dll implemented the now extinct 2-method IDoStuff interface. As one might expect, you will get an exception like this one:
Method ‘DoMoreStuff’ in type ‘the IDoStuff Class inside A.dll’ from assembly ‘strong name of assembly A.dll’ does not have an implementation.
I am presented with two ways that I can think of to deal with this scenario when I’d have to add a method to an existing interface:
1) Update every functionality-providing assembly that uses Stuff.Abstractions.dll to have an implementation of the new ‘DoMoreStuff’ method.
This seems like doing things the hard way, but in a brute-force way would painfully work.
2) Bend the Assumption / Restriction stated above and start allowing more than one Assembly Version to exist (at least for abstraction definition assemblies).
This would be a bit different, and make for a few more assemblies on our servers, but it should allow for the following end state:
A.dll depends on stuff.abstractions.dll, Assembly Version 1.0.0.0, Assembly File Version 1.0.0.22 (AFV doesn’t matter other than identifying the build)
B.dll depends on stuff.abstractions.dll, Assembly Version 1.0.0.1, Assembly File Version 1.0.0.23 (AFV doesn’t matter other than identifying the build)
Both happily able to execute on the same server.
If both versions of stuff.abstractions.dll are installed on the server, then everything should get along fine. A.dll should not need to be altered either. Whenever it needs mods next, you’d have the option to implement a stub and upgrade the interface, or do nothing. Perhaps it would be better to keep it down to the 2 methods it had access to in the first place if it only ever needed them.
As a side benefit, we’d know that anything referencing stuff.abstractions.dll, version 1.0.0.0 only has access to the 2 interface methods, whereas users of 1.0.0.1 have access to 3 methods.
Is there a better way or an accepted deployment pattern for versioning abstractions?
Are there better ways to deal with versioning abstractions if you’re trying to implement a Dependency Inversion scheme in .Net?
Where you have one monolithic application, it seems simple since it’s all contained – just update the interface users and implementers.
The particular scenario I’m trying to solve for is a high code-reuse environment where you have lots of components that depend on lots of components. Dependency Inversion will really help break things up and make Unit Testing feel a lot less like System Testing (due to layers of tight coupling).
Part of the problem may be that you're depending directly on interfaces which were designed with a broader purpose in mind. You can mitigate the problem by having your classes depend on abstractions which were created for them.
If you define interfaces as needed to represent the dependencies of your classes rather than depending on external interfaces, you'll never have to worry about implementing interface members that you don't need.
Suppose I'm writing a class that involves an order shipment, and I realize that I'm going to need to validate the address. I might have a library or a service that performs such validations. But I wouldn't necessarily want to just inject that interface right into my class, because now my class has an outward-facing dependency. If that interface grows, I'm potentially violating the Interface Segregation Principle by depending on an interface I don't use.
Instead, I might stop and write an interface:
public interface IAddressValidator
{
ValidationResult ValidateAddress(Address address);
}
I inject that interface into my class and keep writing my class, deferring writing an implementation until later.
Then it comes time to implement that class, and that's when I can bring in my other service which was designed with a broader intent than just to service this one class, and adapt it to my interface.
public class MyOtherServiceAddressValidator : IAddressValidator
{
private readonly IOtherServiceInterface _otherService;
public MyOtherServiceAddressValidator(IOtherServiceInterface otherService)
{
_otherService = otherService;
}
public ValidationResult ValidateAddress(Address address)
{
// adapt my address to whatever input the other service
// requires, and adapt the response to whatever I want
// to return.
}
}
IAddressValidator exists because I defined it to do what I need for my class, so I never have to worry about having to implement interface members that I don't need. There won't ever be any.
There's always the option to version the interfaces; e.g., if there is
public interface IDoStuff
{
void GoFirst();
void GoSecond();
}
There could then be
public interface IDoStuffV2 : IDoStuff
{
void GoThird();
}
Then ComponentA can reference IDoStuff and ComponentB can be written against IDoStuffV2. Some people frown on interface inheritance, but I don't see any other way to easily version interfaces.
I have a large collection of custom C# classes that roughly follow the MVC pattern that I reuse over and over to build GUI and command line PC applications with different groupings of functionality. For example there are classes for importing and exporting files, classes for manipulating data, classes for monitoring, utility classes, etc.
These classes are currently grouped into a set of assemblies. The higher-level assemblies reference lower-level assemblies, which in turn reference even lower-level assemblies.
All the classes are marked as public so when I build a PC application I can reference the appropriate assemblies and uses the classes in a modular fashion.
When I release a PC application I use a .NET obfuscator to merge the assemblies and the EXE into a single EXE so end users cannot see the APIs of all the classes and assemblies.
Now I would like to create a .NET assembly from my collection of classes that only exposes a specific, limited API and give it to end-users. I guess this is the facade design pattern.
For example I would like to take assemblies A and B and use classes from those, say A.Foo, A.Bar, A.Baz, B.Foobar, B.Bazbar, B.Bazfoo and create a new assembly, C, that has a single public class C.MyClass. Assembly C references assemblies A and B. End users can only see C.MyClass and they can't see or access A.xxx or B.xxx.
Is there a clean way of doing this that doesn't require drastic changes to my current collection of classes and assemblies (as they are already used in multiple other projects)?
Or is this something that is typically handed in the merging/obfuscation stage instead?
Thanks!
I have a project where I want only one class to have access to a dll. I would be content with hiding the dll from intellisense, but still having access to it if that is an option. Either way, I want only one class to use the dll and for it not to be seen and/or accessible otherwise.
I'm using C# in visual studios.
Simply said: You can't do that (but keep reading).
Basically, a DLL (From the .NET perspective) is a bunch of code and config files. No more than that. So, given that you'll need to make public those classes in order to be used from another ones outside that assembly then you can not.
What you can do (I ended up doing this a few years ago) is to use some kind of reflection to determine which class (and namespace) is trying to access your assembly and only permit the proper one.
Other way is to implement a key negotiation between your DLL and the permitted assembly. You'll need to implement those manually, as far as I know.
Anyway, keep in mind there's always a way to bypass this kind of protection by disassembling and modifying your code. So, at least, don't forget to obfuscate the file. Anyway, this will just make it a little more painful, but still possible.
An alternate approach, if you goal is to stop people using the functionality of the dll by accident is to push your wrapper class into an intermediary assembly. Your project then references that intermediary project, rather than the underlying dll which effectively hides it. So your project structure would change to something like this:
Main Project -> references API Wrapper Project -> references API DLL
For this to work, your wrapper project needs to make sure that it doesn't accidentally expose any of the API DLL classes through its public interface.
Obviously this doesn't stop your developers from going in and adding a reference to the API DLL so that they can use the library directly, but if the goal is to stop accidental access to the API DLL classes because intellisense has helped the developer out a bit too much then it might be a viable option.
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've been struggling to do this in a way that fulfills all of my requirements.
Here is what we have in our library:
Base classes for controllers and services
Business objects (stores, departments, etc)
Common Partial Views (Login, Error, etc)
Base class for HttpApplication
General common code (read an INI file, create a db conn, etc)
The one requirement that has been giving me trouble is as follows:
Lives in one place on a server. (i.e. copy local = false)
This breaks because:
The DLL containing the HttpApplication class must be in the same directory as the web apps dll to launch. I haven't found a way around that. I'm ok with duplicating this code in every app, but would rather not.
The shared views don't like to work if I use Assembly.LoadFrom() to load the dll from the shared location. (I've been using this method to precompile my views)
Any namespace shortcuts in web.config break at runtime with compilation errors because the web.config is parsed before the assembly is loaded.
My question to you folks is how do you handle your common code in a similar environment?
The GAC seems to be more trouble than its worth, and we want all of our apps to be using the same code, and not have multiple apps on multiple versions and have to maintain all of that. Are there design patters/best practices that can guide us in this regard?
Also, as a bonus, if you can solve any of the problems above, that would be great, too.
Thanks!
Edit: I guess a question that follows is whether or not we should even have a directory with the common dll(s) on the server, or if they should only be deployed as projects are deployed/updated?
Firstly, you will want to separate out what you're trying to achieve. Don't create 1 library that does everything or you will have a Big Ball of Mud. Don't be afraid to create several maintainable libraries to achieve what you're after. Is there a specific reason it needs to be stored in one location?
For example, several of the items you mention are MVC or web specific. If you have items that can be reused by MVC, create a class library that contains MVC base classes you inherit and reference them in your project. Use the single responsibility principle as much as possible.
Regarding the other items you mentioned, like database connectivity, if it's reusable, abstract it out in a data access class library and reference it. Other simple operations like reading an ini file or creating a file, create another library and abstract it to easy to use methods.
I prefer to copy the library dlls locally. You never know when you will need to make changes to the library, but you don't want all of your projects to stop compiling. When you're ready to implement a new version of the library, copy the dll in and recompile.
Not sure why all the hate towards the gac. It was designed to handle this specific problem. Install your common dlls to the gac and all apps can see them. Need to deploy a new one, just re-install it in one place.