Creating Custom Actions For Dynamics 365 With C#

Custom Actions are lesser used processes than Workflows and Plugins in Dynamics 365, but very useful also at the same time. For people who have already have an idea of Custom Workflow Activity (or read my previous article), it’s going to be very easy. The coding part is the same, only "how we consume the code in Dynamics 365 process" is different, and use cases too, obviously. Custom Actions can be created with or without writing code, but they can be triggered only by the code. Here, we will write custom code to retrieve the case records assigned to calling users.

Step 1 - Create New Project

In Visual Studio, create a new project of type Class Library & select framework version 4.5.2. This might change for future versions. I have given the name as MyCasesAction, which tells the purpose of the workflow.

Dynamics CRM

Step 2 - Add Required Packags

Go to Manage NuGet Packages and install Microssoft.CrmSdk.CoreAssemblies (for Microsoft.Xrm.Sdk namespace) & Microssoft.CrmSdk.Workflow (for Microsoft.Xrm.Sdk.Workflow namespace).

Dynamics CRM

Step 3 - Create MyCasesAction Class

Create a class MyCasesAction inherited from CodeActivity. It will need to add System.Activities namespace.

  1. using System.Activities;  
  2. namespace MyCasesAction {  
  3.     public class MyCasesAction: CodeActivity {  
  4.         protected override void Execute(CodeActivityContext context) {}  
  5.     }  
  6. }  
Step 4 - Adding Parameters

We will have 2 output parameters - one containing count of cases, the other having the name of cases separated by commas. We will take the user’s GUID from context.

  1. using Microsoft.Xrm.Sdk.Workflow;  
  2. using System.Activities;  
  3. namespace MyCasesAction {  
  4.     public class MyCasesAction: CodeActivity {  
  5.         [Output("Count of Cases")]  
  6.         public OutArgument < int > CaseCount {  
  7.                 get;  
  8.                 set;  
  9.             }  
  10.             [Output("Name of Cases")]  
  11.         public OutArgument < string > CaseNames {  
  12.             get;  
  13.             set;  
  14.         }  
  15.         protected override void Execute(CodeActivityContext context) {}  
  16.     }  
  17. }  
Step 5 - Adding Logic to Retrieve User Cases
  1. using Microsoft.Xrm.Sdk;  
  2. using Microsoft.Xrm.Sdk.Query;  
  3. using Microsoft.Xrm.Sdk.Workflow;  
  4. using System.Activities;  
  5. using System.Collections.Generic;  
  6. namespace MyCasesAction {  
  7.     public class MyCasesAction: CodeActivity {  
  8.         [Output("Count of Cases")]  
  9.         public OutArgument < int > CaseCount {  
  10.                 get;  
  11.                 set;  
  12.             }  
  13.             [Output("Name of Cases")]  
  14.         public OutArgument < string > CaseNames {  
  15.             get;  
  16.             set;  
  17.         }  
  18.         protected override void Execute(CodeActivityContext context) {  
  19.             // Getting OrganizationService from Context  
  20.             var workflowContext = context.GetExtension < IWorkflowContext > ();  
  21.             var serviceFactory = context.GetExtension < IOrganizationServiceFactory > ();  
  22.             var orgService = serviceFactory.CreateOrganizationService(workflowContext.UserId);  
  23.             // fetchXml to retrieve cases for current user  
  24.             var fetchXmlCurrentUserCases = @ " < fetch version = '1.0'  
  25.             output - format = 'xml-platform'  
  26.             mapping = 'logical'  
  27.             distinct = 'false' > < entity name = 'incident' > < attribute name = 'title' / > < filter type = 'and' > < condition attribute = 'ownerid'  
  28.             operator = 'eq-userid' / > < /filter> < /entity> < /fetch>";  
  29.             // Retrieving cases using fetchXml  
  30.             var cases = orgService.RetrieveMultiple(new FetchExpression(fetchXmlCurrentUserCases));  
  31.             // Null check  
  32.             if (cases == null || cases ? .Entities == nullreturn;  
  33.             // Adding Case names/titles to list  
  34.             var allCases = new List < string > ();  
  35.             foreach(var cs in cases.Entities)  
  36.             allCases.Add(cs["title"].ToString());  
  37.             // Set Count of cases to CaseCount  
  38.             CaseCount.Set(context, cases.Entities.Count);  
  39.             // Set comma separated Case Titles to CaseNames  
  40.             CaseNames.Set(context, string.Join(",", allCases.ToArray()));  
  41.         }  
  42.     }  
  43.  
Step 6 - Signing the Assembly

In Dynamics 365, it is necessary to sign the assembly before registering. To do this:

  1. Right click on project, click on Properties to open.
  2. On the left pane, click on Signing.
  3. Check "Sign the assembly" checkbox.
  4. In "Choose a strong name key file" dropdown, click New…
  5. "Create Strong Name Key" popup will appear.
  6. Give some name.
  7. Optionally, you can protect this key file with a password.
  8. Click OK to generate the key and sign the assembly.
  9. Build the solution.
Dynamics CRM

Step 7 - Register the Assembly in Dynamics 365

Open the Plugin Registration Tool and connect with your organization. If you don’t already have it, grab it by adding Microsoft.CrmSdk.XrmTooling.PluginRegistrationTool NuGet Package.

  1. Click on Register, then Register New Assembly.

    Dynamics CRM

  2. Register New Assembly popup will appear, select your project DLL from bin/debug folder of the project.

    Dynamics CRM

  3. After selecting DLL, make sure that the Select All is selected in Step 2.

    Dynamics CRM

  4. Leave the rest of the options as they are and click Register Selected Plugins, it should register your assembly successfully.
  5. You can verify the assembly after registering in Plugin Registration Tool.

    Dynamics CRM
Step 8 - Creating Custom Action in CRM and Consuming MyCasesAction
  1. Go to the Solution, create a new process, set name as “Get My Cases”, set category as “Action” & in the entity, I’m setting it as “None (global)”. If we will select some entity here, our action will get one default input parameter of the same type as given entity.

    Dynamics CRM

  2. Add two output arguments with the same type as output parameters given in MyCasesAction class. However, the names do not need to be the same but you can keep them the same to avoid confusion.

    Dynamics CRM

  3. Click on "Add Step" and look for your assembly; i.e MyCasesAction. Click on it and select MyCasesAction.MyCasesAction step.

    Dynamics CRM

  4. The step added from assembly will return case count and names, which should be set to output arguments. Add “Assign Value” step for both arguments.

    Dynamics CRM

  5. Click on “Set Properties” in Assign Value to set output argument value. Do it for both “CaseCount” & “CaseNames”.


  6. Save your process and click on “Activate” to activate it.

    Dynamics CRM

  7. It will ask for confirmation; click “Activate” to confirm.

    Dynamics CRM

Congratulations! You have successfully created Custom Action. Let’s test it now.

Step 9 - Testing Your Custom Action

As I mentioned above, Custom Actions can be triggered with code only. I will be using Dynamics 365 Console Caller to test our code, you can download this by following https://github.com/AshV/Dynamics365ConsoleCaller.

You need to grab Unique Name/Logical Name of your process, which is id new_GetMyCases in our case.

Dynamics CRM

After downloading Dynamics 365 Console Caller open in Visual Studio and open Program.cs. Provide connection details & add code to test your custom action.

  1. using Microsoft.Crm.Sdk.Messages;  
  2. using Microsoft.Xrm.Sdk;  
  3. using System;  
  4. using static System.Console;  
  5. namespace Dynamics365ConsoleCaller {  
  6.     class Program // BUILD BEFORE RUN TO RESTORE NuGet PACKAGES  
  7.     {  
  8.         static void Main(string[] args) {  
  9.             IOrganizationService orgService = Connect.GetOrganizationService("[email protected]""Your-Passowrd""https://Org.crm.dynamics.com");  
  10.             Console.WriteLine("Connected to Organization Service!");  
  11.             ITracingService tracingService = Connect.GetTracingService("AshV_Log");  
  12.             // Write Your Testing Code here.  
  13.             var executeAction = orgService.Execute(new OrganizationRequest() {  
  14.                 RequestName = "new_GetMyCases",  
  15.             });  
  16.             var caseCount = executeAction["CaseCount"];  
  17.             var caseNames = executeAction["CaseNames"];  
  18.             WriteLine($ "Count of Cases : {caseCount}");  
  19.             WriteLine($ "Name Cases : {caseNames}");  
  20.         }  
  21.     }  
  22. }  

Run the above code to test and verify your custom action. 

Thanks for reading, I hope it’s helpful.


Similar Articles