This is not a problem. You can even host and plug-in whole WPF applications. I think you don't need this, so I'll explain a skeleton of plug-in design.
Let's assume you have host application which never changes (more exactly, its plug-in support sub-system is not changed or is changed incrementally, see below) and several plug-ins with possibility of changing plug-ins and developing new plug-ins. Pluggable at the very beginning of run-time is easy, reloadable is possible but way more difficult; the problem here is not loading, but unloading, because unloading of assembly is impossible; you can only unload Application Domain.
1) First, you should avoid matching of any type of member by name. This is quite possible. You need to develop a plug-in interface. Define interface type and keep in mind you should never change is from the moment you start developing plug-in implementations. More exactly, you can make interfaces upgradeable. For this purpose, you can add additional functionality in the derived interfaces. In other words, you need to keep interface changed incremental (never remove methods). The plug-in interface(s) will be your contract with plug-ins.
2) Make the definition(s) of your plug-in interfaces(s) accessible to both he host application and plug-in. It looks trivial, because you do it using a separate assembly referenced by both host and all plug-ins. You can do better! You can keep the interfaces and all helper types to be used by plug-ins in your application. It will help you to keep consistent versioning (no different assemblies — no different versions). Not everyone knows that you can reference your whole application (*.exe) in another assembly as any DLL. Essentially, .NET does not know difference between EXE and DLL (in contrast to native Windows).
3) Now, you need to recognize a plug-in in the plug-in assembly loaded from file. You can do it traversing all top-level types in assembly and checking is any of them support one of your plug-in interfaces. Trivial? And what if more than one class supports the plug-in interface? What if there are too many classes? You can do better! Create a custom attribute of assembly which helps to claim some type supporting a plug-in interface. Every plug-in should have something like this:
[assembly: ExposePlugin(
typeof(TextProcessor),
typeof(MyDataImporter),
typeof(MyDataExporter))]
(Just in case this sample is not clear: the type
ExposePluginInterface
does not exist, I suggest you develop it.)
In this way, your host plug-in support does not traverse all assembly types but only those listed in the isntance of
ExposePluginInterface
.
4) A plug-in concept in interesting: each plug-in implements plug-in interface and passes implementation to the host; and host passes required host resources to plug-in. You implement the plug-in using those resources. (This is a note to item (1).) Now you can implement plug-ins and load them in the host. It leaves for the problem: how can you unload it?
5) Unloading of plug-ins is much more difficult. You should understand that Application Domains have totally isolated data. You cannot simply add control from one
AppDomain
to another. Application Domains can only communication through IPC. However, you can use highly simplified form of IPC, see
System.AppDomain.SetData
,
System.AppDomain.GetData
. There is a problem passing any data containing reference data, as the reference is only valid in the source
AppDomain
, so you can only assembly a deep clone on the other end. So, you hardly can pass UI controls between this boundary.
Here is one idea: you should not try to share control data between
AppDomains
. You can develop meta-data which only contains the instructions on how to assembly the controls on the host site. Make you plug-in interfaces more semantic. Of course, you can always share code between two
ApplicationDomains
and pass data (but only add data) through the method parameters.
[EDIT]
6) See this on how to run the code in the context of the newly created
AppDomain
:
AppDomain refuses to load an assembly[
^]
The idea is using
System.AppDomain.DoCallBack
or (less likely as it required the plugin-in with the entry point (EXE file)
System.AppDomain.ExecuteAssembly
.
[END EDIT]
You don't have to develop whole plug-in architecture is this way. Alternatively, you can take the other way around. In place of plug-in you can develop separate applications, each representing semantics of what you now consider a plug-in. The plug-ins will be your UI presentation libraries. Imagine you create several Presentation Foundations on your own, but simple and specialized. In particular, you should know how to run a WPF application in a library. If you're interested, ask another Question, but the answer might be a whole separate article. I actually successfully used both ways; which one to take depends on your ultimate goals.
Good luck,
—SAP.S.: Please see another Answer for follow-up discussion.