Yes, you can do it. Here is the method:
First of all, the plug-in architecture has the dependencies on the following functional units: 1) host application, 2) an interface or a set of interfaces (optional or not) which a plug-in should implement; 3) a in interface or a set of interfaces which the host application should implement (mandatory) and pass the interface reference(s) to the instance of a plug-in; it could be as simple as
WriteLine
, for example; 4) one or more plug-in implementations.
I hope you can show by yourself what depends on what. Basically, both plug-in and host code depend on all interfaces.
Now, the trick is, in its simplest variant: you can put all parts except (4) in one assembly: the host application!
The question is how? Do you think a project can only reference an object library assembly? No, there is no essential difference between EXE, DLL or anything like that. An assembly is an assembly. Any assembly can referenced by any other assembly. In your case, you should put all interfaces and host-side implementation is the assembly of the host application (if can reference any number of other assemblies, of course, but not with the interfaces mentioned above) and
each plug-in should add a reference to the entry assembly of your host application.
In case you still did not get it, here is the note: It won't create any circular dependencies. In this scenario, each plug-in depends only on the entry assembly on the host application. The host application itself does not depend on plug-ins; only it run-time depends on them, but it does not ruin anything.
This really works, I did it in a few projects.
Now, the only missing piece is: how to prevent replacing of the host assembly by a forged one? The solution is well-known: make an entry assembly of the host application
strongly named by giving it a
digital signature; don't pass a private key and the source code to the user.
Of course,
almost nothing can prevent reverse engineering. But even with the reverse engineering, no one can reverse engineer just the main system and then use the plug-ins without limitations. This person would need to
reverse engineer each plug-in, no less, so she or he won't be able to create a "final" solution and, say, cell it — this solution won't be able to work with legitimate or new plug-ins.
Please see my past solutions on plug-in architecture:
Create WPF Application that uses Reloadable Plugins...[
^],
AppDomain refuses to load an assembly[
^],
code generating using CodeDom[
^],
Create WPF Application that uses Reloadable Plugins...[
^],
Dynamically Load User Controls[
^],
how to Catch an unhandled exception thrown from a sub domain when calling a method by inkove(reflection)[
^].
—SA