Microsoft has added a new feature into the .NET framework, it’s now possible to create extensible applications using System.Addin. To me this sounded perfect as this makes creating extensible applications a whole lot easier. The opposite however is true, it’s a rather complex web of structures and rules that you need to be aware of when attempting to build an add-in.
In this first part I will talk about the basic structure of the add-ins model in .NET 3.5 and what basic rules apply.
The basic structure of an application that makes use of add-ins is composed of roughly three parts. You have the host, the contract and the add-in. Each of these parts is contained in its own assembly.
Surrounding the contract assembly there are two more parts that I haven’t pointed out here. At the host side of the contract there’s the host-side adapter assembly and at the add-in side of the contract there’s the add-in side adapter assembly. Together with the contract these parts form the add-in pipeline.
The adapters are used to convert between the host base classes and the client base classes. These base classes are implemented in separate assemblies that are used in the host and add-in assemblies.
The complete structure contains at least 7 assemblies that are linked in such a way that there’s isolation between the host and the add-in, but also an isolation layer between the contract and the host and an isolation layer between the contract and the add-in (These are formed by the adapter assemblies).
The reason for the appdomain isolation in this model is that add-ins should be unloadable during runtime. This is achieved by combining the isolation between host and add-in with separate appdomains. Each add-in is loaded in a separate appdomain, which can be unloaded at any moment.
The contract isolation layer is needed for versioning. By adding contract isolation layer it’s possible to version the host independently from the add-ins, because they only require the assembly containing the add-in component model (The assembly containing the add-in base classes).
The add-ins can also version independently from the host, because the host only needs the component model for the host.
To version the host and the add-ins independently from each other you need to upgrade the adapter assemblies each time you change the interface of the contract or the host/add-in side of the adapter.
Crossing the boundary
There’s one thing that is somewhat limited with the implementation that Microsoft choose. There are a lot of restrictions on what types can be exchanged through the add-in contract.
The following types can be passed through the contract interface:
- Other contracts
- Serializable types in the contract assembly (These must be simple structs, there can be no implementation attached to the type passed through the interface)
- Primitive types (Boolean,int,double)
- Enums (Either from the .NET framework or the contract assembly)
- Serializable system types (Must be sealed, otherwise it doesn’t work. String is one of the possibilities)
At this point it’s not possible to let MarshalByRefObjects cross the contract boundary between the host and the add-in. This is to prevent problems with versioning. Serializable types can be fixed during serialization and deserialization using the ISerializable interface and the IDeserializationCallback interface. MarshalByRefObjects don’t have this feature and cause versioning problems when you upgrade the host, contract or add-in interface.
There’s also a restriction on value types. The official reading from Microsoft is that you can only pass Valuetypes that can only be loaded once per appdomain. This basically means that you can only use valuetypes from the .NET framework as the framework is only loaded once per appdomain.
In the above list I omitted arrays. Arrays can be passed, however only with valuetypes. If you want to pass reference types you need to use the IListContract <T> interface.
With these restrictions applying on the contract, you can’t really create systems where the add-ins show visual components on the host meaning you can’t create windows forms add-ins. Microsoft however did create the possibility in WPF to create add-ins that can add UI components from the add-in on the host UI.
The new add-in system is complex, you need a lot of components to actually get a simple add-in working. However this system does solve the problem with leaking types between appdomains and versioning problems that occur when upgrading components independently from eachother.
In the next post I will show a sample on how to create a basic add-in with visual components in WPF. For a really basic sample I refer to a blogpost of Guy Burstein.