XrmToolBox has plenty of useful plugins, and awesome people like you from community keep adding new plugins to solve Dynamics 365 developer’s day to day hurdles and make them more productive. Recently I was working on an XrmToolBox plugin (have a look at GitHub Dynamics 365 Bulk Solution Exporter). Let me share my learning experience with you.
Start by taking a class library project and installing XrmToolBoxPackage using NuGet. You need to create one Custom Windows Form Control in this approach. I created Dynamics 365 Bulk Solution Exporter this way because the template was not available back then.
Tanguy Touzard (Creator of XrmToolBox) has simplified the process by creating XrmToolBox Plugin Project Template for Visual Studio, which configures most of the things automatically. This is the preferred way of creating plugins now.
You won’t be getting this project template by default in Visual Studio, to install goto new project dialog, navigate to online section in the left pane and search for XrmToolBox in the right pane; the template will appear in the result. Install it. Visual Studio needs to be restarted in order to install the template.

After installing, create a new Project using this template. Framework version should be selected as 4.6.2.

You will get 2 main files in the newly created project where you need to work on.
MyPlugin.csThis file contains metadata like the name of the plugin, icons, and color etc., which you can change according to the purpose of your plugin. I am changing the name of the plugin to “WhoAmI Plugin”.
- using System.ComponentModel.Composition;
- using XrmToolBox.Extensibility;
- using XrmToolBox.Extensibility.Interfaces;
- namespace XrmToolBox.WhoAmIPlugin
- {
- // Do not forget to update version number and author (company attribute) in AssemblyInfo.cs class
- // To generate Base64 string for Images below, you can use https://www.base64-image.de/
- [Export(typeof(IXrmToolBoxPlugin)),
- ExportMetadata("Name", "WhoAmI Plugin"),
- ExportMetadata("Description", "This is a description for my first plugin"),
- // Please specify the base64 content of a 32x32 pixels image
- ExportMetadata("SmallImageBase64", null),
- // Please specify the base64 content of a 80x80 pixels image
- ExportMetadata("BigImageBase64", null),
- ExportMetadata("BackgroundColor", "Lavender"),
- ExportMetadata("PrimaryFontColor", "Black"),
- ExportMetadata("SecondaryFontColor", "Gray")]
- public class MyPlugin : PluginBase
- {
- public override IXrmToolBoxPluginControl GetControl()
- {
- return new MyPluginControl();
- }
- }
- }
This file help you to save/update any configuration value permanently, which will be available when you next time open the tool.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace XrmToolBox.WhoAmIPlugin
- {
- /// <summary>
- /// This class can help you to store settings for your plugin
- /// </summary>
- /// <remarks>
- /// This class must be XML serializable
- /// </remarks>
- public class Settings
- {
- public string LastUsedOrganizationWebappUrl { get; set; }
- }
- }
This is a Windows Form Control which is composed of 3 files.
- MyPluginControl.cs[Design]
This file contains the UI where we can pull the controls from Toolbox and make the Plugin UI what user will interact with. - MyPluginControl.designer.cs
This files contains autogenerated code, which is generated while we are placing and configuring controls in UI using drag & drop. we don’t need to directly interact with this file. - MyPluginControl.cs
This is where we need bind our logic to different events generated from UI, like ButtonClick, OnLoad etc. This file is shown below, is contains some sample code which retrieves count of Account records and displays to user.
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Drawing;
- using System.Data;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows.Forms;
- using XrmToolBox.Extensibility;
- using Microsoft.Xrm.Sdk.Query;
- using Microsoft.Xrm.Sdk;
- using McTools.Xrm.Connection;
- namespace XrmToolBox.WhoAmIPlugin
- {
- public partial class MyPluginControl : PluginControlBase
- {
- private Settings mySettings;
- public MyPluginControl()
- {
- InitializeComponent();
- }
- private void MyPluginControl_Load(object sender, EventArgs e)
- {
- ShowInfoNotification("This is a notification that can lead to XrmToolBox repository", new Uri("https://github.com/MscrmTools/XrmToolBox"));
- // Loads or creates the settings for the plugin
- if (!SettingsManager.Instance.TryLoad(GetType(), out mySettings))
- {
- mySettings = new Settings();
- LogWarning("Settings not found => a new settings file has been created!");
- }
- else
- {
- LogInfo("Settings found and loaded");
- }
- }
- private void tsbClose_Click(object sender, EventArgs e)
- {
- CloseTool();
- }
- private void tsbSample_Click(object sender, EventArgs e)
- {
- // The ExecuteMethod method handles connecting to an
- // organization if XrmToolBox is not yet connected
- ExecuteMethod(GetAccounts);
- }
- private void GetAccounts()
- {
- WorkAsync(new WorkAsyncInfo
- {
- Message = "Getting accounts",
- Work = (worker, args) =>
- {
- args.Result = Service.RetrieveMultiple(new QueryExpression("account")
- {
- TopCount = 50
- });
- },
- PostWorkCallBack = (args) =>
- {
- if (args.Error != null)
- {
- MessageBox.Show(args.Error.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- var result = args.Result as EntityCollection;
- if (result != null)
- {
- MessageBox.Show($"Found {result.Entities.Count} accounts");
- }
- }
- });
- }
- /// <summary>
- /// This event occurs when the plugin is closed
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void MyPluginControl_OnCloseTool(object sender, EventArgs e)
- {
- // Before leaving, save the settings
- SettingsManager.Instance.Save(GetType(), mySettings);
- }
- /// <summary>
- /// This event occurs when the connection has been updated in XrmToolBox
- /// </summary>
- public override void UpdateConnection(IOrganizationService newService, ConnectionDetail detail, string actionName, object parameter)
- {
- base.UpdateConnection(newService, detail, actionName, parameter);
- mySettings.LastUsedOrganizationWebappUrl = detail.WebApplicationUrl;
- LogInfo("Connection has changed to: {0}", detail.WebApplicationUrl);
- }
- }
- }






Michael BlackburnPosted Apr 13, 2019, 6:14 AM
Can we get "publishing" guide you teased? Very helpful blog!
Pavan Mani Deep YaraganiPosted Mar 9, 2019, 8:52 PM
Thanks Ashish...well elucidated!!!