VSTO Performance: Ribbon Reflection (Stephen Peters)

It is very easy to customize the Ribbon in your VSTO extension.  All you need to do is to add a Ribbon (Visual Designer) to your solution, and it will appear when your solution is run without needing to do any more work.  Behind the scenes, the VSTO runtime reflects through your entire addin assembly looking for Ribbon extensions to instantiate.  This reflection can cause a significant performance hit, especially on larger solutions.

During an addin’s startup, the VSTO Runtime needs to discover and instantiate any user-created Ribbon extensions.  The runtime does this by calling CreateRibbonExtensibilityObject, which is implemented by VSTO in the addin base class.  It will then call CreateRibbonObjects, another method on the addin base class.  This implementation of CreateRibbonObjects will reflect over every type in the addin assembly looking for classes that implement Microsoft.Office.Tools.Ribbon.IRibbonExtension (4.0) or Microsoft.Office.Tools.Ribbon.OfficeRibbon (3.5), instantiating each one, and then returns these in an array.

The performance hit comes from the reflection that happens in CreateRibbonObjects.  For simple VSTO addins, this isn’t very significant.  But if you link in a large library, then the reflector will pull in any types referenced in your assembly, and any types that those types reference, and so forth.  This can result in having to spend a lot of time reading these types from disk, and it is completely unavoidable. 

In order to avoid this, we can override either of these two methods so that the default implementation of CreateRibbonObjects is not called.  If the addin has no ribbons, then it’s best to override CreateRibbonExtensibilityObject in order to execute as little code as possible.

protected override Office.IRibbonExtensibility 
    CreateRibbonExtensibilityObject()
{
    return null;
}

If your addin includes a Ribbon, then it’s better to override CreateRibbonObjects.  Note that if you are creating an addin for .Net 3.5, you’ll need to return OfficeRibbon[] instead of IRibbonExtension[].

using Microsoft.Office.Tools.Ribbon;
protected override IRibbonExtension[] CreateRibbonObjects()
{
    return new IRibbonExtension[] { new Ribbon1(), new Ribbon2() };
}

In our perf lab, we ran some benchmarks using the method described in this blog entry to generate the numbers.  Of interest were two tests involving an Outlook addin that had a Form Region with a single WPF control, before and after removing the Ribbon reflection.  The results were that removing reflection saved over a second off of the cold startup time.  So if you have larger VSTO solutions you may want to try to this technique to speed up performance.