Steps to develop an AddIn using Managed AddIn Framework (MAF)

I had blogged earlier about Managed AddIn Framework and the resources to learn the basics. Making use of System.AddIn framework features can appear complex for beginners. In this example we develop a host application and AddIn using Managed AddIn Framework.

Source Code: You can download the source code for this example below.

 Source Code 

The diagram below demonstrates how we are going to implement each component in the Managed AddIn Framework in our sample application.

clip_image001

When you activate an Addin from host, you can load the Addin in its own application domain or in an existing application domain or even in a new process separate from host’s process.

Step -1 – HostView

Create a solution with the following solution folders. Create a class library project named HostView under the Pipeline solution folder.

It is important to set the project settings. For HostView, change the output path to ..\output\ (Visual Studio default will be \bin\debug or \bin\release)

The HostView is an abstract class with methods corresponding to the methods exposed by the Addin. In this example I go for a simple method which returns the sum of two integer numbers.

namespace Demo.HostView
{
    public abstract class HostView
    {
        public abstract int ComputeSum(int a, int b);
    }
}

Step -2 – Create Host Application

Create a Windows Application project named SampleHost under the HostApplication solution folder.

clip_image003 

  1. Change the output path to ..\output\

  2. Add reference to assemblies System.AddIn and System.AddIn.Contract

  3. Add reference to project HostView

The host application UI is given below. It aims to load our addin and use it for computing the sum of numbers supplied from the host application.

clip_image005

Add the following code in the Host to load the AddIn

Collection<AddInToken> _addinTokens;
Collection<HostView> _addinList = new Collection<HostView>();
HostView calcAddin;

private void btn_Load_Click(object sender, EventArgs e)
{
    LoadAddins();
}

public void LoadAddins()
{
    // Set root directory for finding Add-ins
    string addinRoot = Environment.CurrentDirectory;

    // Rebuild the add-ins and pipeline components 
    AddInStore.Rebuild(addinRoot);

    // Find add-ins of type HostView
    _addinTokens = AddInStore.FindAddIns(typeof(HostView), addinRoot);

    foreach (AddInToken addinToken in _addinTokens)
    {
        // Activate the add-in
        _addinList.Add(
            addinToken.Activate<HostView>(AddInSecurityLevel.Internet));

        // Display Addin-Details
        richText1.AppendText(String.Format("Loaded Add-in {0} Version {1}",
            addinToken.Name, addinToken.Version));
    }

    calcAddin = _addinList[0];
}
And we are ready to use the addin instance. 
private void btn_Add_Click(object sender, EventArgs e)
{
    if (calcAddin != null)
    {
        //Invoking the AddIn method
        int sum = calcAddin.ComputeSum(
            Convert.ToInt32(textBox1.Text), 
            Convert.ToInt32(textBox2.Text));
        lblResult.Text = sum.ToString();
    }
    else
        MessageBox.Show("AddIn is not loaded"); 
}

Step -3 –Create AddIn View

Create a class library project named AddInView under the Pipeline solution folder.

  • Change the output path to ..\output\AddInViews\

  • Add reference to assemblies System.AddIn and System.AddIn.Contract

The AddInView is an abstract class with methods corresponding to the methods exposed by the Addin. Note that this class should have the attribute [AddInBase]

using System.AddIn.Pipeline;
namespace Demo.AddinView
{
    [AddInBase]
    public abstract class AddInView
    {
        public abstract int ComputeSum(int a, int b);
    }
}

Step – 4 – Create Contract

The contract in the middle of the pipeline is loaded into both Host’s app domain and AddIn’s app domain.

Create a class library and;

  • Change the output path to ..\output\Contracts\
  • Add reference to assemblies System.AddIn and System.AddIn.Contract

 

clip_image007

 

The contract interface should have the [AddInContract] attribute as shown below.

using System.AddIn.Contract;
using System.AddIn.Pipeline;

namespace Demo.Contracts
{
    [AddInContract]
    public interface IContracts:IContract
    {
        int ComputeSum(int a, int b);
    }
}

Step -5 –Create Host Side Adapter

The host-side converts the flow of types between Host View and the contract.

Create a class library project named HostSideAdapters under the Pipeline solution folder

 

  • Change the output path to ..\output\HostSideAdapters\

  • Add reference to assemblies System.AddIn and System.AddIn.Contract

  • Add reference to project Contracts, set Copy Local property to False

  • Add reference to project HostView, set Copy Local property to False

 

clip_image009

Note the [HostAdapter] attribute of the ContractToHostViewAdapter Class below.

using System.AddIn.Pipeline;
using Demo.Contracts;
namespace Demo.HostSideAdapters
{
    [HostAdapter]
    public class ContractToHostViewAdapter : HostView.HostView
    {
        private IContracts _calcContract;
        private ContractHandle _handle;
        public ContractToHostViewAdapter(IContracts contract)
        {
            _calcContract = contract;
            _handle = new ContractHandle(_calcContract);
        }
        public override int ComputeSum(int a, int b)
        {
            return this._calcContract.ComputeSum(a,b);
        }
    }
}

 

Step -6 – Create AddIn Side Adapter

Create a class library project named AddInSideAdapters under the Pipeline solution folder

 

  • Change the output path to ..\output\AddInSideAdapters\

  • Add reference to assemblies System.AddIn and System.AddIn.Contract

  • Add reference to project Contracts, set Copy Local property to False

  • Add reference to project AddInView, set Copy Local property to False

 

clip_image011

Note the [AddInAdapter] attribute of the AddInViewToContractAdapter Class below. The adapter inherits from System.AddIn.Pipeline.ContractBase class and implements  IContracts interface.

using System.AddIn.Pipeline;
using Demo.AddinView;
using Demo.Contracts;
namespace Demo.AddInSideAdapters
{
    [AddInAdapter]
    public class AddInViewToContractAdapter: ContractBase, IContracts
    {
        private AddInView _view;
        public AddInViewToContractAdapter(AddInView view)
        {
            this._view = view;
        }
        public int ComputeSum(int a, int b)
        {
            return this._view.ComputeSum(a,b);
        }
     }
}

Step -7 –Implement AddIn

Create a class library project named CalcAdd under the AddIn solution folder

Change the output path to ..\output\AddIns\CalcAddin\  (If you have multiple Addin, each AddIn would be deployed into separate directories)

  • Add reference to assemblies System.AddIn and System.AddInx.Contract

  • Add reference to project AddInView, set Copy Local property to False

clip_image013

namespace Demo.CalcAddIn
{
    [System.AddIn.AddIn("Demo Add-In", 
     Version = "1.0.0.0",
     Description = "Description of Demo AddIn", 
     Publisher = "XYZ Company")]
    public class CalcAddIn : Demo.AddinView.AddInView
    {
        public override int ComputeSum(int a, int b)
        {
            return a+b;
        }
    }
}

Step -8 – Run the host application

Build the solution and run the host application. You should see the following result.

clip_image015

Alternately you can download the source code from the link below and run it.

Source Code

Advertisements

Pipeline Builder Tool – Making the AddIin development easy

The CLR Add-in team came up with a very useful tool to save the coding effort and complexity associated with add-in development. The tool is available in CodePlex.

I installed the pipeline builder add-in to Visual Studio 2008 and it works great!  Matt Hidinger in his blog describes the steps to use pipeline builder with a sample.

The links that may be of interest to add-in developers are :