-
Notifications
You must be signed in to change notification settings - Fork 2
Plugins
Dataverse powertools has a number of features to assist with the management of plugins in Dataverse. These features include:
- Creating and updating plugins, plugin steps, and custom workflow steps
- Deploying plugins using spkl
- Registering both plugin and workflow steps using spkl. This extension helps with the creation of the spkl decorations for plugin and workflow step registrations.
- Xunit Tests utilising FakeXrmEasy for dataverse fakes.
To get started with Plugins, you will need to initialise your project. This can be done by selecting Initialize Project from the command palette or side bar. This will create a instance of the Plugins template, restore dependencies and create a new Plugin class called sampleClass.ts as well as a a new Workflow class called sampleWorkflow.ts. The following options will now be available in the command palette or side bar:

This option will restore the local dependencies onto your PC. This is done for you automatically as part of the Initialize Project command. However it will be needed if you add additional dependencies to your project or if you are working on a project that has been cloned from a repository.
To generate Early Bound classes select Generate Early Bound from the command palette or side bar. This will create a new folder called generated within ProjectName and add the classes to this folder. Note: This will need to be done each time the underlying schema changes.
You can modify list of tables and actions that get earlybound classes generated from within spkl.json or by using the Earlybound Options interface in the side bar.

To add a table select it from the list of available tables that have been fetched from dataverse. Press the refresh button to update the list.

To remove a table or action click the red X when hovering over the item.

To manually add a table or to add an action click on the + when hovering over the root menu item.

This will automatically update your spkl.json. You will need to click generate early bourd once complete to generate the new classes.
To create a new Plugin or Workflow class, right click on the ProjectName folder and select either Dataverse Powertools: Create Plugin Class or Dataverse Powertools: Create Workflow Class.
Note: ProjectName_ will be the actual the name of your project / namespace.

Visual Studio Code will then ask you for the name of the new class. This will be the name of the class that is created and the name of the file. Note: The name of the class must be unique.
Note: The ProjectName.csproj is configured to include all files within the ProjectName folder so no manual changes are required to the project file.
A sample of a new plugin class file is below:
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.Xrm.Sdk;
namespace PluginSRC
{
// Sample decroation, this will register the below step as part of the publish. Decorations can be added manually or via the Add Plugin Decoration command.
// They must appear above the class declaration and must be uncommented. A unique GUID is required for each decoration, the builtin command will do this for you.
// [CrmPluginRegistration(MessageNameEnum.Create, "contact", StageEnum.PostOperation, ExecutionModeEnum.Synchronous, "", "PluginSRC - ClassName - Create", 1, IsolationModeEnum.Sandbox, Id = "90705ddd-1442-4403-8cb6-48807e2ecaf7")]
public class ClassName : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
ITracingService tracer = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService userService = factory.CreateOrganizationService(context.UserId);
IOrganizationService systemService = factory.CreateOrganizationService(null);
using (var userServiceContext = new XrmSvc(userService))
using (var systemServiceContext = new XrmSvc(systemService))
{
// Do stuff
}
}
}
}A sample of a new workflow class file is below:
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.Xrm.Sdk;
using System.Activities;
using Microsoft.Xrm.Sdk.Workflow;
namespace PluginSRC
{
//[CrmPluginRegistration("WorkflowActivity","ClassName", "Workflow Description", "Workflow Group Name", IsolationModeEnum.Sandbox)]
public class ClassName : CodeActivity
{
[RequiredArgument]
[Input("Contact")]
[ReferenceTarget("contact")]
public InArgument<EntityReference> Contact { get; set; }
protected override void Execute(CodeActivityContext executionContext)
{
ITracingService tracingService = executionContext.GetExtension<ITracingService>();
IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
IOrganizationServiceFactory factory = executionContext.GetExtension<IOrganizationServiceFactory>();
IOrganizationService userService = factory.CreateOrganizationService(context.UserId);
IOrganizationService systemService = factory.CreateOrganizationService(null);
using (var userServiceContext = new XrmSvc(userService))
using (var systemServiceContext = new XrmSvc(systemService))
{
// Do stuff
}
}
}
}Thanks to spkl, this extension is able to register both plugin steps and custom workflow steps as part of the publish process. This is done by adding a decoration to the class. The decoration can be added manually or by using the Add Plugin Decoration command. this can be found in the command menu or the Dataverse PowerTools sidebar.
For Plugins, the command will ask you for the following information:
- Message Name that the step will be registered against
- Name of the entity that the step will be registered against
- Stage of execution that the step will be registered against (Pre-Validation, Pre-Operation, Post-Operation)
- Exection Mode of the step (Synchronous or Asynchronous)
- List of filtering attributes. Comma separated list of attributes that will be used to filter the step. If the step is not filtered then leave this blank.
- Step Name. This is the name of the step that will be registered. This must be unique.
- Order of execution. This is the order that the step will be registered.
- Isolation Mode. This is the isolation mode that the step will be registered as. Sandbox or None. Use Sandbox for Online environments.
- Id. This is the Id of the step. This is a unique GUID and will be generated for you.
For Workflows, the command will ask you for the following information:
- Name of the Workflow Activity. This is the name of the class that will be registered.
- Description of the Workflow Activity. This is the description that will be displayed in the workflow designer.
- Group Name of the Workflow Activity. This is the group name that will be displayed in the workflow designer.
- Isoaltion Mode. This is the isolation mode that the step will be registered as. Sandbox or None. Use Sandbox for Online environments.
Plugins will be build and released in Debug mode when using VSCode. To build and deploy the plugins in Debug mode use the Dataverse PowerTools: Build and Deploy Plugins command. This will build the plugins and deploy them to the Dataverse environment that is configured in the project. To build and deploy workflows use the Dataverse PowerTools: Build and Deploy Workflows command in a similar matter.
If you wish to manually deploy you can build locally by using the Dataverse PowerTools: Build Project command. This will build the plugins and workflows in Debug mode.
As part of the Azure DevOps Plugin build pipelines the plugins are rebuilt and saved as artifacts to be bundled into the managed solution as part of the solution build pipelines.
This extension also creates a Tests project under the ProjectName_tests folder. It utilises Xunit and FakeXrmEasy to create tests for your plugins. The tests are run as part of the Azure DevOps build pipelines. The tests can be run locally by running the dotnet test command from the ProjectName_tests folder.
The following is a sample test class:
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using FakeXrmEasy;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Xunit;
namespace PluginSRC.Tests
{
public class PluginTest
{
// Write tests here
// Sample code
//
[Fact]
public void Test_contact()
{
var fakedContext = new XrmFakedContext { ProxyTypesAssembly = Assembly.GetExecutingAssembly() };
var fakedService = fakedContext.GetOrganizationService();
fakedContext.ProxyTypesAssembly = Assembly.GetExecutingAssembly();
fakedContext.ProxyTypesAssembly = Assembly.GetAssembly(typeof(contact));
var target = new contact { Id = Guid.NewGuid(), firstname = "bob" };
fakedContext.Initialize(new List<Entity>{ target });
ParameterCollection inputParameters = new ParameterCollection
{
{ "Target", target }
};
fakedContext.ExecutePluginWith<CLASSNAME>(inputParameters,null,null,null);
using (var systemServiceContext = new XrmSvc(fakedService))
{
contact returnedSession = systemServiceContext.contactSet.First();
Assert.Equal("bob", returnedSession.firstname);
}
}
}
}See the FakeXrmEasy documentation for more information on how to use FakeXrmEasy.
Configure a variable group to store the credentials for the Dataverse environment. To do this, navigate to the project settings and select Variable Groups under Pipelines. Select + Variable Group and give the group the name DevEnv.
Add a variable called ConnectionString with the value of the connection string for the Dataverse environment. Note: The connection string should be in the format:
AuthType=ClientSecret;Url=https://<orgname>.crm.dynamics.com;ClientId=<clientid>;ClientSecret=<clientsecret>;
Once the variable group has been created, configure the permissions (7) so that either the web resources pipeline or all pipelines have access to these variables.

Create the build pipleine from the templated azure-pipelines.yml file in the root of the repository. This should be the same process as show in the solutions page under "Create a pipeline".
Once the pipeline has been configured it will output the following artifacts:

The outputted dll file will be in release mode and ready for consumption by the solution build pipeline for release into upstream environments.
Tests and Code Coverage tabs will be available within DevOps after the build pipeline has run, see examples of the output below:
