How To: Build an Add-In using System.AddIn
How To: Build an Add-In using System.AddIn
When you want to build an extensible application, that dynamically loads add-ins into it, you face some challenges such as discovering, activating and managing the lifetime of the add-ins. With the new System.AddIn Framework that ships with Visual Studio 2008, this tasks becomes much easier.
This post is a step by step guide for building a *very* simple add-in using the new System.AddIn Framework. I will guide you through building a Console Application that actives add-ins and runs them. In later posts I will discuss how to version the host and add-ins separately, talk about less trivial scenarios and provide feedback about this process which I hope the team will collect.
Create the Solution
Create a new solution in Visual Studio 2008, and create the following structure using solution folders.
Create the Host Side
Host View
The Host View defines the way the host sees the add-ins.
Create the Host View of the add-in. Create a Class Library under the Host Side Solution Folder.
Set the output directory of the host application project to be ..\output instead of bin\debug. This is because the discovery and pipeline building phases require a certain directory structure that will be discussed later.
Create a class for the simple add-in host view. This class is an abstract class with the operations that the host will call on the add-in.
/// <summary>
/// The host view defines the how the host sees the add-in
/// </summary>
public abstract class SimpleAddInHostView
{
public abstract string SayHello(string name);
}
Host application
The host application actives and manages the lifetime of the add-ins.
Create the Host application as a Console Application under the Host Side Solution Folder.
Set the output folder of the host view project to be ..\output\.
Set this project as start up project.
Add references to System.AddIn and System.AddIn.Contract assemblies. Also add a reference to the Host.View project.
In the Main method of the host application, write the following code:
static void Main(string[] args)
{
// Set the add-ins discovery root directory to be the current directory
string addinRoot = Environment.CurrentDirectory;
// Rebuild the add-ins cache and pipeline components cache.
AddInStore.Rebuild(addinRoot);
// Get registerd add-ins of type SimpleAddInHostView
Collection<AddInToken> addins = AddInStore.FindAddIns(typeof(SimpleAddInHostView), addinRoot);
foreach (AddInToken addinToken in addins)
{
// Activate the add-in
SimpleAddInHostView addinInstance =
addinToken.Activate<SimpleAddInHostView>(AddInSecurityLevel.Internet);
// Use the add-in
Console.WriteLine(String.Format("Add-in {0} Version {1}",
addinToken.Name, addinToken.Version));
Console.WriteLine(addinInstance.SayHello("Guy"));
}
}
This code snippet rebuilds the cache of the add-ins store and the pipeline components. Then, the host is looking for add-ins of type SimpleAddIn and uses them.
Create the Add-In Side
Add-In Views
The add-in views define the base class for the add-ins. It is the way the add-in receives the calls from the host.
Create the AddIn Views project as a Class Library under the AddIn Side Solution Folder.
Set the output folder of the host view project to be ..\output\AddInViews\.
Add references to System.AddIn and System.AddIn.Contract assemblies.
Create a class for the simple add-in view. This class is an abstract class with the operations that the host will call on the add-in. This class is decorated with the AddInBase attribute. This attribute is important when building the pipeline.
/// <summary>
/// The add-in view defines the how the add-in sees how it is
/// called by the host
/// </summary>
[AddInBase]
public abstract class SimpleAddInView
{
public abstract string SayHello(string name);
}
Add-In Implementation
The host can activate many add-ins. Each add-in derives from the add-in view and is deployed in a separate directory.
Create each Add-In Implementation project as a Class Library under the AddIn Side\AddIns Solution Folder. In the samples I created 2 add-ins.
Set the output folder of the host view project to be ..\output\AddIns\<AddInName>. (For example: ..\output\first\ and ..\output\second).
For each add-in implementation project, add references to System.AddIn and System.AddIn.Contract assemblies. Also add a reference to the AddIn.View project, but make sure you set Copy Local = False.
Implement the add-ins. Create a class that derives from the AddIn View class (SimpleAddInView), and decorated with the AddIn attribute. This attribute specifies the matedata of the add-in.
[AddIn("My First Add-In",
Version="1.0.0.0",
Description="Description of My First Add-In",
Publisher="Guy Burstein")]
public class FirstAddIn : SimpleAddInView
{
public override string SayHello(string name)
{
return "Hi, " + name;
}
}
Create the Pipeline Components
Usually, we prefer that the add-ins will be activated isolated in a separate AppDomain for better sandboxing and robustness of the host application. This isolation brings the need for inter-appdomain communication that is addressed by building the appropriate pipeline between the host and the add-in.
The Contract
The minimal interface between the host and the add-in is expressed by a contract. This contract cannot be versioned.
Create the Contract project as a Class Library under the Contracts Solution Folder.
Set the output folder of the host view project to be ..\output\Contracts.
Add references to System.AddIn and System.AddIn.Contract assemblies.
Create an interface for the contract. This interface contain the operations that the host will call on the add-in.
/// <summary>
/// This interface defines the contract between the host and the add-in, and
/// therefore cannot be versioned.
/// </summary>
[AddInContract]
public interface ISimpleContract : IContract
{
string SayHello(string name);
}
Notice that this interface derives from IContract interface and is decorated by the AddInContract attribute.
Host Side Adapter
The host side adapter is responsible for converting from the contract to the host view. This way, the host view has no dependency on the contract and can be versioned independently.
In this sample, the host calls methods on the add-in, and not the opposite. Therefore, we only need an adapter from the Contract to the Host View.
Create the Host Adapters project as a Class Library under the Host Side Solution Folder.

Set the output folder of the host view project to be ..\output\HostSideAdapters.
Add references to System.AddIn and System.AddIn.Contract assemblies. Also add a reference to Host.View and Contracts projects, but make sure you set Copy Local = False.
Implement the adapter. This adapter derives from the host view, and as an implementation calls method on an instance referenced by the contract interface.
/// <summary>
/// This class converts a contract instance to the host view
/// </summary>
[HostAdapter]
public class SimpleContractToHostViewAdapter : SimpleAddInHostView
{
private ISimpleContract _contract;
private ContractHandle _handle;
public SimpleContractToHostViewAdapter(ISimpleContract contract)
{
this._contract = contract;
_handle = new ContractHandle(contract);
}
public override string SayHello(string name)
{
return this._contract.SayHello(name);
}
}
Notice that the constructor initiates an instance of ContractHandle which helps the lifetime management of the add-in.
Add In Adapter
The add-in side adapter is responsible for converting from the add-in view to the contract. This way, the add-in view has no dependency on the contract and can be versioned independently.
In this sample, the host calls methods on the add-in, and not the opposite. Therefore, we only need an adapter from the Add-In View to the contract.
Create the Add-In Adapters project as a Class Library under the AddIn Side Solution Folder.
Set the output folder of the host view project to be ..\output\AddInSideAdapters.
Add references to System.AddIn and System.AddIn.Contract assemblies. Also add a reference to AddIn.View and Contracts projects, but make sure you set Copy Local = False.
Implement the adapter. This adapter derives from the BaseContract, implements the contract, and as an implementation calls method on an instance of the add-in view.
/// <summary>
/// This class converts an add-in view to the contract
/// </summary>
[AddInAdapter]
public class SimpleAddInViewToContractAdapter : ContractBase, ISimpleContract
{
private SimpleAddInView _view;
public SimpleAddInViewToContractAdapter(SimpleAddInView view)
{
this._view = view;
}
public string SayHello(string name)
{
return this._view.SayHello(name);
}
}
Running the Sample
You can download the sample project that contain the simple add-in created with System.AddIn in this post. Running this sample, you should see this result:
Additional Resources
Enjoy!