We did not talk about anything about versioning. Versioning is a big challenge for Host and AddIn developers. Whenever Host or AddIn has an upgrade, versioning and compatibility becomes a big problem. Our AddIn model is trying to solve the versioning issue in V1. Our solution is to have a model that Host and AddIn will not depend on each other. More than that, we introduced the idea of Contract as an isolation boundary. Host, Contract and AddIn will have their own versions independent with each other. Here is the example of a Contract.

 

namespace PaintDotNetAddInContract

{

    [AddInContract]

    public interface IPDNEffectContract : IContract

    {

        void Render();

    }

}

 

The attribute above informs our discovery API that this class is a Contract that we can connect it with other AddIn pipeline components during activation. When we load AddIn in a separate AppDomain, Contract will be the AppDomain boundary.

 

Since we want the versions to be independent, Host, Contract and AddIn cannot reference each other. We have to introduce another term called “Adapter”.  Adapters are the components to connect different versioned components. For example the adapter to connect Host and Contract is called HostAdapter. Here is the code sample for HostAdapter.

 

namespace PaintDotNetHostAdapter

{

    [HostAdapter]

    public class PDNHostAdapter : AddInHSV

    {

        IPDNEffectContract contract;

        public PDNHostAdapter(IPDNEffectContract contract)

        {

            this.contract = contract;

            LifetimeTokenHandle handle = new LifetimeTokenHandle(contract);

        }

        public override void Render(EffectConfigToken parameters, PaintDotNet.RenderArgs dstArgs, PaintDotNet.RenderArgs srcArgs, System.Drawing.Rectangle[] rois, int startIndex, int length)

        {

            contract.Render();

        }

    }

}

 

We also have a special attribute defined for HostAdapter for discovery. As you may notice that HostAdapter is actually derived from Host Side View and it takes the Contract as a constructor parameter. That is how it connects Host and the Contract.

The benefit of having Adapter is that Adapter code is usually small and easy to update. Whenever we have a versioning change at either side of the Adapter, we can always update the Adapter and the whole pipeline will still work.

 

We did not explain LifetimeTokenHandle and IContract yet. It is related to certain functionalities that all AddIn should have like lifetime management, contract enumeration etc. Our AddIn model has an easy way for AddIn developers to get those functionalities automatically.

 

Our next topic will be IContract, ContractBase and AddInAdapter.