Tutorial: Write and register a plug-in

This tutorial is the first in a series that will show you how to work with plug-ins. This tutorial is a pre-requisite for the following tutorials:

For detailed explanation of supporting concepts and technical details see:

Goal

Create an asynchronous plug-in registered on the Create message of the account entity. The plug-in will create a task activity that will remind the creator of the account to follow up one week later.

Note

This goal can be easily achieved using a workflow without writing code. We are using this simple example so that we can focus on the process of creating and deploying a plug-in.

Prerequisites

  • Administrator level access to a Common Data Service environment
  • A model-driven app that includes the account and task entities.
  • Visual Studio 2017
  • Knowledge of the Visual C# programming language
  • Download the Plug-in Registration tool.
    • Information about downloading the Plug-in registration tool is at : Download tools from NuGet. That topic includes instructions to use a PowerShell script to download the latest tools from NuGet.

Create a plug-in project

You need to use Visual Studio to write a plug-in. Use these steps to write a basic plug-in. Alternately, you can find the complete plug-in solution files here: Sample: Create a basic plug-in.

Create a Visual Studio Project for the Plug-in

  1. Open Visual Studio 2017 and open a new Class Library (.NET Framework) project using .NET Framework 4.6.2

    open a new Class Library (.NET Framework) project using .NET Framework 4.6.2

    The name used for the project will be the name of the assembly. This tutorial uses the name BasicPlugin.

  2. In Solution Explorer, right-click the project and select Manage NuGet Packages… from the context menu.

    Manage NuGet packages

  3. Select Browse and search for Microsoft.CrmSdk.CoreAssemblies and install the latest version.

    Install Microsoft.CrmSdk.CoreAssemblies NuGet Package

  4. You must select I Accept in the License Acceptance dialog.

  5. In Solution Explorer, right-click the Class1.cs file and choose Rename in the context menu.

    Rename class

  6. Rename the Class1.cs file to FollowupPlugin.cs.

  7. When prompted, allow Visual Studio to re-name the class to match the file name.

    Confirm rename dialog

Edit the Class file to enable a plug-in

  1. Add the following using statements to the top of the FollowupPlugin.cs file:

    using System.ServiceModel;  
    using Microsoft.Xrm.Sdk;
    
  2. Implement the IPlugin Interface by editing the class.

    Note

    If you just type : IPlugin after the class name, Visual Studio will auto-suggest implementing a stub for the Execute Method.

    public class FollowupPlugin : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            throw new NotImplementedException();
        }
    }
    
  3. Replace the contents of the Execute method with the following code:

// Obtain the tracing service
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));

// Obtain the execution context from the service provider.  
IPluginExecutionContext context = (IPluginExecutionContext)
    serviceProvider.GetService(typeof(IPluginExecutionContext));

// The InputParameters collection contains all the data passed in the message request.  
if (context.InputParameters.Contains("Target") &&
    context.InputParameters["Target"] is Entity)
{
    // Obtain the target entity from the input parameters.  
    Entity entity = (Entity)context.InputParameters["Target"];

    // Obtain the organization service reference which you will need for  
    // web service calls.  
    IOrganizationServiceFactory serviceFactory =
        (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
    IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

    try
    {
        // Plug-in business logic goes here.  
    }

    catch (FaultException<OrganizationServiceFault> ex)
    {
        throw new InvalidPluginExecutionException("An error occurred in FollowUpPlugin.", ex);
    }

    catch (Exception ex)
    {
        tracingService.Trace("FollowUpPlugin: {0}", ex.ToString());
        throw;
    }
}

About the code

Add business logic

The plug-in will create a task activity that will remind the creator of the account to follow up one week later.

Add the following code to the try block. Replace the comment: // Plug-in business logic goes here. with the following:

// Create a task activity to follow up with the account customer in 7 days. 
Entity followup = new Entity("task");

followup["subject"] = "Send e-mail to the new customer.";
followup["description"] =
    "Follow up with the customer. Check if there are any new issues that need resolution.";
followup["scheduledstart"] = DateTime.Now.AddDays(7);
followup["scheduledend"] = DateTime.Now.AddDays(7);
followup["category"] = context.PrimaryEntityName;

// Refer to the account in the task activity.
if (context.OutputParameters.Contains("id"))
{
    Guid regardingobjectid = new Guid(context.OutputParameters["id"].ToString());
    string regardingobjectidType = "account";

    followup["regardingobjectid"] =
    new EntityReference(regardingobjectidType, regardingobjectid);
}

// Create the task in Microsoft Dynamics CRM.
tracingService.Trace("FollowupPlugin: Creating the task activity.");
service.Create(followup);

About the code

Build plug-in

In Visual Studio, press F6 to build the assembly. Verify that it compiles without error.

Sign plug-in

  1. In Solution Explorer, right click the BasicPlugin project and in the context menu select Properties.

    Open project properties

  2. In the project properties, select the Signing tab and select the Sign the assembly checkbox.

    Sign the assembly

  3. In the Choose a strong name key file: dropdown, select <New…>.

  4. In the Create Strong Name Keydialog, enter a key file name and deselect the Protect my key file with a password checkbox.

  5. Click OK to close the Create Strong Name Key dialog.

  6. In the project properties Build tab, verify that the Configuration is set to Debug.

  7. Press F6 to build the plug-in again.

  8. Using windows explorer, find the built plug-in at: \bin\Debug\BasicPlugin.dll.

Note

Build the assembly using Debug configuration because you will use the Plug-in profiler to debug it in a later tutorial. Before you include a plug-in with your solution, you should build it using the release configuration.

Register plug-in

To register a plug-in, you will need the plug-in registration tool

Connect using the Plug-in Registration tool

  1. After you have downloaded the Plug-in registration tool, click the PluginRegistration.exe to open it.

  2. Click Create new Connection to connect to your instance.

  3. Make sure Office 365 is selected. If you are connecting using a Microsoft account other than one you are currently using, click Show Advanced.

    Logging in with the Plug-in registration tool

  4. Enter your credentials and click Login.

  5. If your Microsoft Account provides access to multiple environments, you will need to choose an environment.

  6. After you are connected, you will see any existing registered plug-ins & custom workflow activities

    View existing plug-ins an custom workflow activities

Register your assembly

  1. In the Register drop-down, select New Assembly.

    Register new assembly

  2. In the Register New Assembly dialog, select the ellipses () button and browse to the assembly you built in the previous step.

    Register new assembly dialog

  3. For Office 365 users, verify that the isolation mode is sandbox and the location to store the assembly is Database.

    Note

    Other options for isolation mode and location apply to on-premises Dynamics 365 deployments. For the location, you can specify the D365 server's database, the server's local storage (disk), or the server's Global Assembly Cache. For more information see Plug-in Storage.

  4. Click Register Selected Plug-ins.

  5. You will see a Registered Plug-ins confirmation dialog.

    Registerd plug-ins confirmation dialog

  6. Click OK to close the dialog and close the Register New Assembly dialog.

  7. You should now see the (Assembly) BasicPlugin assembly which you can expand to view the (Plugin) BasicPlugin.FollowUpPlugin plugin.

    (Plugin) BasicPlugin.FollowUpPlugin plugin.

Register a new step

  1. Right-click the (Plugin) BasicPlugin.FollowUpPlugin and select Register New Step.

    Register a new step

  2. In the Register New Step dialog, set the following fields:

    Setting Value
    Message Create
    Primary Entity account
    Event Pipeline Stage of Execution PostOperation
    Execution Mode Asynchronous

    Register a new step

  3. Click Register New Step to complete the registration and close the Register New Step dialog.

  4. You can now see the registered step.

    View the registered step

Note

At this point the assembly and steps are part of the system Default Solution. This is a good time to add them to the unmanaged solution you will distribute. These steps are not included in this tutorial. See Add your assembly to a solution and Add step to solution for more information.

Test plug-in

  1. Open a model-driven app and create an account entity.

  2. Within a short time, open the account and you can verify the creation of the task.

    Account entity record with related task activity create by plug-in

What if the task wasn't created?

Because this is an asynchronous plug-in, the operation to create the task occurs after the account is created. Usually, this will happen immediately, but if it doesn't you may still be able to view the system job in the queue waiting to be applied. This step registration used the Delete AsyncOperation if StatusCode = Successful option which is a best practice. This means as soon as the system job completes successfully, you will not be able to view the system job data unless you re-register the plug-in with the Delete AsyncOperation if StatusCode = Successful option unselected.

However, if there was an error, you can view the system job to see the error message.

View System jobs

Use the Dynamics 365 --custom app to view system jobs.

  1. In your model-driven app, navigate to the

    view the dynamics 365 custom app

  2. In the Dynamics 365 --custom app, navigate to Settings > System > System Jobs.

    navigate to system jobs

  3. When viewing system jobs, you can filter by Entity. Select Account.

    foo

  4. If the job failed, you should see a record with the name BasicPlugin.FollowupPlugin: Create of account

    Failed system job

  5. If you open the system job, you can expand the Details section to view the information written to the trace and details about the error.

    system job details

Query System jobs

You can use the following Web API query to return failed system jobs for asynchronous plug-ins

GET <your org uri>/api/data/v9.0/asyncoperations?$filter=operationtype eq 1 and statuscode eq 31&$select=name,message

More information: Query Data using the Web API

Or use the following FetchXml:

<fetch top='50' >
  <entity name='asyncoperation' >
    <attribute name='message' />
    <attribute name='name' />
    <filter type='and' >
      <condition attribute='operationtype' operator='eq' value='1' />
      <condition attribute='statuscode' operator='eq' value='31' />
    </filter>
  </entity>
</fetch>

More information: Use FetchXML with FetchExpression

View trace logs

The sample code wrote a message to the trace log. The steps below describe how to view the logs.

By default, plug-in trace logs are not enabled.

Tip

IF you prefer to change this setting in code: This setting is in the Organization Entity PluginTraceLogSetting attribute.

The valid values are:

Value Label
0 Off
1 Exception
2 All

Use the following steps to enable them in a model-driven app.

  1. Open the Dynamics 365 - custom app.

    Open the Dynamics 365 - custom  app

  2. Navigate to Settings > System > Administration.

    navigate to administration

  3. In Administration, select System Settings.

  4. In the System Settings dialog, in the customization tab, set Enable logging to plug-in trace log to All.

    System Settings Customization tab

    Note

    You should disable logging after you are finished testing your plug-in, or at least set it to Exception rather than All.

  5. Click OK to close the System Settings dialog.

  6. Repeat the steps to test your plug-in by creating a new account.

  7. In the Dynamics 365 -- custom app, navigate to Settings > Customization > Plug-In Trace Log.

  8. You should find that a new Plug-in Trace Log record has been created.

    Plug-in trace log record

  9. If you open the record you might expect that it would include the information you set in your trace, but it does not. It only verifies that the trace occurred.

  10. To see the details, it is easier to query this data using the Web API in your browser using the following query with the plugintracelog EntityType, using the typename property to filter results in the messageblock property based on the name of the plug-in class:

    GET <your org uri>/api/data/v9.0/plugintracelogs?$select=messageblock&$filter=typename eq 'BasicPlugin.FollowUpPlugin'

  11. You can expect to see the following returned with the Web API query:

    {
        "@odata.context": "<your org uri>/api/data/v9.0/$metadata#plugintracelogs(messageblock)",
        "value": [{
            "messageblock": "FollowupPlugin: Creating the task activity.",
            "plugintracelogid": "f0c221d1-7f84-4f89-acdb-bbf8f7ce9f6c"
        }]
    }
    

Next steps

In this tutorial you have created a simple plug-in and registered it. Complete Tutorial: Debug a plug-in to learn how to debug this plug-in.