The Loader Framework


One interesting little API gem is the ExtensionLoader.  Well, it’s interesting to me because I designed it, but maybe you will find it interesting too.  I basically took the mechanism for loading plug-ins and made it public in the API.  In theory, you can make use of this tool to load extensions of your own.  Another use is interrogating the system to see which Vault plug-ins are available, where they live, what their settings are, and so on.

In order to be loaded by the framework, a plug-in has to meet certain requirements.

  • The plug-in has to work through an interface.
  • The plug-in needs a class that implements the interface.
  • The loader app needs to be aware of the interface.
  • The implementing class needs a default constructor.
  • There needs to be .vcet.config file, which is what tells the loader framework about the plug-in.

If you take a closer look at the .vcet.config for a 2014 plug in, you will notice that an <extension> contains an interface and typeInterface can be anything you want.  IExplorerExtension, IJobHandler and IWebServiceExtension are the ones provided by the Vault API.  But the loader framework doesn’t care about that.  It will work with any .NET interface.  Type is the class that implements the interface.  The Loader creates a new instance of that class when loading the plug-in.


The loader framework can be access through the ExtensionLoader, which is in Autodesk.Connectivity.Extensibility.Framework.  Here is a quick example I put together.  It’s for an EXE that prints out the Vault Explorer extensions along with their custom commands and tabs.

// C#

using Autodesk.Connectivity.Extensibility.Framework;

using Autodesk.Connectivity.Explorer.Extensibility;

 

 

ExtensionLoader loader = newExtensionLoader();

 

// load the plug-ins matching the IExplorerExtension interface

var extensions = loader.LoadExtensions<IExplorerExtension>();

foreach (Extension<IExplorerExtension> extension in extensions)

{

    output.AppendLine("Extension " +

        extension.ExtensionAssembly.ProductName);

   

    // create a new instance of the plug-in

    // we are not going to run it

    // we just want to read data from it

    IExplorerExtension explorerExt = extension.NewInstance();

 

    // ask the plug-in for it's commands

    IEnumerable<CommandSite> customCommands =

        explorerExt.CommandSites();

    if (customCommands != null && customCommands.Any())

    {

        output.AppendLine("- Custom commands: ");

        foreach (CommandSite site in customCommands)

        {

            foreach (CommandItem command in site.CommandItems)

            {

                output.AppendLine("– " + command.Label);

            }

        }

    }

 

    // ask the plug-in for it's custom tabs

    IEnumerable<DetailPaneTab> customTabs =

        explorerExt.DetailTabs();

    if (customTabs != null && customTabs.Any())

    {

        output.AppendLine("- Custom tabs: ");

        foreach (DetailPaneTab tab in customTabs)

        {

            output.AppendLine("– " + tab.Label);

        }

    }

}

' VB.NET

Imports Autodesk.Connectivity.Extensibility.Framework

Imports Autodesk.Connectivity.Explorer.Extensibility

 

 

Dim loader AsNewExtensionLoader()

 

' load the plug-ins matching the IExplorerExtension interface

Dim extensions = loader.LoadExtensions(OfIExplorerExtension)()

ForEach extension AsExtension(OfIExplorerExtension) In extensions

    output.AppendLine("Extension " + extension.ExtensionAssembly.ProductName)

 

    ' create a new instance of the plug-in

    ' we are not going to run it

    ' we just want to read data from it

    Dim explorerExt AsIExplorerExtension = extension.NewInstance()

 

    ' ask the plug-in for it's commands

    Dim customCommands AsIEnumerable(OfCommandSite) = _

        explorerExt.CommandSites()

    If customCommands IsNotNothingAndAlso customCommands.Any() Then

        output.AppendLine("- Custom commands: ")

        ForEach site AsCommandSiteIn customCommands

            ForEach command AsCommandItemIn site.CommandItems

                output.AppendLine("– " + command.Label)

            Next

        Next

    EndIf

 

    ' ask the plug-in for it's custom tabs

    Dim customTabs AsIEnumerable(OfDetailPaneTab) = _

        explorerExt.DetailTabs()

    If customTabs IsNotNothingAndAlso customTabs.Any() Then

        output.AppendLine("- Custom tabs: ")

        ForEach tab AsDetailPaneTabIn customTabs

            output.AppendLine("– " + tab.Label)

        Next

    EndIf

Next

 


Here is what the output looks like on my computer.  As you can expect, I have a good number of plug-ins installed.

Extension AdvancedAdvancedFind
– Custom commands:
— Advanced Advanced Find…
Extension Deco
Extension EffectiveFolderPermissions
– Custom commands:
— Effective Permissions
— Permissions Overview
— Administrator List
— Settings
— Effective Permissions
— Effective Permissions
Extension Thunderdome
– Custom commands:
— Backup Vault Settings
— Create Deployment
Extension VaultWebView
– Custom commands:
— Configure Web View…
– Custom tabs:
— Web View 1
— Web View 1
— PLM 360

It’s not quite perfect.  Duplicates show up because the command/tab shows up in different contexts.  Also, DECO does have custom commands, but they are not shown here.  The reason is that the plug-in was loaded outside the context of Vault Explorer, and DECO doesn’t like that.



Comments

6 responses to “The Loader Framework”

  1. Andreas Wagner Avatar
    Andreas Wagner

    is it possible to get / call a Vault-Command?
    for example the “go to folder” or “change state” commands

  2. Sorry, no. You can’t run out-of-the box commands from a custom command.
    However there is a way to navigate to a folder when your custom command exits: http://justonesandzeros.typepad.com/blog/2012/07/gotolocation.html

  3. Hi Doug, is it possible to navigate to a folder in a custom tab with a custom context menu?

  4. No, a tab view cannot change the navigation context of Vault Explorer.

  5. Doug, love your articles. However, I have one question about this one. Above you mentioned: •The plug-in needs a class that impalements the interface
    Did you really mean impalements? LOL! Everybody misspells a word or two every now and then.

  6. Yep, that was a typo. Thanks for letting me know.

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading