Write a plug-in

 

Applies To: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online

Plug-ins are custom classes that implement the IPlugin interface. You can write a plug-in in any .NET Framework 4.5.2 CLR-compliant language such as Microsoft Visual C# and Microsoft Visual Basic .NET. To be able to compile plug-in code, you must add Microsoft.Xrm.Sdk.dll and Microsoft.Crm.Sdk.Proxy.dll assembly references to your project. These assemblies can be found in the SDK\Bin folder of the SDK. Download the Microsoft Dynamics CRM SDK package.

In This Topic

Plug-in design

Writing a Basic Plug-in

Write a Plug-in Constructor

Support Offline Execution

Web Access for Isolated (sandboxed) Plug-ins

Use Early-Bound Types

Plug-in Assemblies

Plug-in design

Your plug-in design should take into account the web application auto-save feature introduced in Microsoft Dynamics 365 (online & on-premises). Auto-save is enabled by default but can be disabled at an organization level. When auto-save is enabled there is no Save button. The web application will save data in the form automatically 30 seconds after the last unsaved change. You can apply form scripts to disable the auto-save behaviors on a form level. Depending on how you registered your plug-in, auto-save may result in your plug-in being called more frequently for individual field changes instead of one plug-in invocation for all changes. You should assume that any user can save any record at any time, whether this is done using Ctrl+S, by pressing a save button, or automatically due to the auto-save feature.

It is a best practice to register your plug-in or workflow on entities and specific fields that matter most. Avoid registering a plug-in or workflow for changes to all entity fields. If you have an existing plug-or workflow that was implemented before the availability of the auto save feature, you should re-test that code to verify its proper operation. For more information see TechNet: Manage auto-save.

Writing a Basic Plug-in

The following sample shows some of the common code found in a plug-in. For this sample, the code omits any custom business logic that would perform the intended task of the plug-in. However, the code does show a plug-in class that implements the IPlugin interface and the required Execute method.

using System;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;

public class MyPlugin: IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        // Extract the tracing service for use in debugging sandboxed plug-ins.
        // If you are not registering the plug-in in the sandbox, then you do
        // not have to add any tracing service related code.
        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"];

            // Verify that the target entity represents an entity type you are expecting. 
            // For example, an account. If not, the plug-in was not registered correctly.
            if (entity.LogicalName != "account")
                return;

            // 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 MyPlug-in.", ex);
            }

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

The IServiceProvider parameter of the Execute method is a container for several service useful objects that can be accessed within a plug-in. The service provider contains instance references to the execution context, IOrganizationServiceFactory, ITracingService, and more. The sample code demonstrates how to obtain references to the execution context, IOrganizationService, and ITracingService from the service provider parameter. For more information about the tracing service, refer to Debug a plug-In.

The execution context contains a wealth of information about the event that caused the plug-in to execute and the data contained in the message that is currently being processed by the pipeline. For more information about the data context, see Understand the data context passed to a plug-in.

The platform provides the correct Web service URLs and network credentials when you obtain the organization Web service reference from the service provider. Instantiating your own Web service proxy is not supported because it creates deadlock and authentication issues. After you have the organization service reference, you can use it to make method calls to the organization Web service. You can retrieve or change business data in a single Microsoft Dynamics 365 organization by issuing one or more message requests to the Web service. For more information about message requests, see Use messages (request and response classes) with the Execute method.

A typical plug-in should access the information in the context, perform the required business operations, and handle exceptions. For more information about handling exceptions in a plug-in, refer to Handle exceptions in plug-ins. A more complete plug-in sample is available in the topic Sample: Create a basic plug-in.

Important

For improved performance, Microsoft Dynamics 365 caches plug-in instances. The plug-in's Execute method should be written to be stateless because the constructor is not called for every invocation of the plug-in. Also, multiple system threads could execute the plug-in at the same time. All per invocation state information is stored in the context, so you should not use global variables or attempt to store any data in member variables for use during the next plug-in invocation unless that data was obtained from the configuration parameter provided to the constructor. Changes to a plug-ins registration will cause the plug-in to be re-initialized.

Write a Plug-in Constructor

The Microsoft Dynamics 365 platform supports an optional plug-in constructor that accepts either one or two string parameters. If you write a constructor like this, you can pass any strings of information to the plug-in at run time.

The following sample shows the format of the constructor. In this example, the plug-in class is named SamplePlugin.

public SamplePlugin()
public SamplePlugin(string unsecure)
public SamplePlugin(string unsecure, string secure)

The first string parameter of the constructor contains public (unsecure) information. The second string parameter contains non-public (secure) information. In this discussion, secure refers to an encrypted value while unsecure is an unencrypted value. When using Microsoft Dynamics 365 for Microsoft Office Outlook with Offline Access, the secure string is not passed to a plug-in that executes while Dynamics 365 for Outlook is offline.

The information that is passed to the plug-in constructor in these strings is specified when the plug-in is registered with Microsoft Dynamics 365. When using the Plug-in Registration tool to register a plug-in, you can enter secure and unsecure information in the Secure Configuration and Unsecure Configuration fields provided in the Register New Step form. When registering a plug-in programmatically using the Microsoft Dynamics 365 SDK, SdkMessageProcessingStep.Configuration contains the unsecure value and SdkMessageProcessingStep.SecureConfigId refers to a SdkMessageProcessingStepSecureConfig record that contains the secure value.

Support Offline Execution

You can register plug-ins to execute in online mode, offline mode, or both. Offline mode is only supported on Microsoft Dynamics 365 for Microsoft Office Outlook with Offline Access. Your plug-in code can check whether it is executing in offline mode by checking the IsExecutingOffline property.

When you design a plug-in that will be registered for both online and offline execution, remember that the plug-in can execute twice. The first time is while Microsoft Dynamics 365 for Microsoft Office Outlook with Offline Access is offline. The plug-in executes again when Dynamics 365 for Outlook goes online and synchronization between Dynamics 365 for Outlook and the Microsoft Dynamics 365 server occurs. You can check the IsOfflinePlayback property to determine if the plug-in is executing because of this synchronization.

Web Access for Isolated (sandboxed) Plug-ins

If you plan on registering your plug-in in the sandbox, you can still access Web addresses from your plug-in code. You can use any .NET Framework class in your plug-in code that provides Web access within the Web access restrictions outlined Plug-in isolation, trusts, and statistics. For example, the following plug-in code downloads a Web page.


// Download the target URI using a Web client. Any .NET class that uses the
// HTTP or HTTPS protocols and a DNS lookup should work.
using (WebClient client = new WebClient())
{
    byte[] responseBytes = client.DownloadData(webAddress);
    string response = Encoding.UTF8.GetString(responseBytes);
System_CAPS_security Security Note

For sandboxed plug-ins to be able to access external Web services, the server where the Sandbox Processing Service role is installed must be exposed to the Internet, and the account that the sandbox service runs under must have Internet access. Only outbound connections on ports 80 and 443 are required. Inbound connection access is not required. Use the Windows Firewall control panel to enable outbound connections for the Microsoft.Crm.Sandbox.WorkerProcess application located on the server in the %PROGRAMFILES%\Microsoft Dynamics 365\Server\bin folder.

Use Early-Bound Types

To use early-bound Microsoft Dynamics 365 types in your plug-in code simply include the types file, generated using the CrmSvcUtil program, in your Microsoft Visual Studio plug-in project.

Conversion of a late-bound entity to an early-bound entity is handled as follows:

Account acct = entity.ToEntity<Account>();

In the previous line of code, the acct variable is an early-bound type. All Entity values that are assigned to IPluginExecutionContext must be late-bound types. If an early-bound type is assigned to the context, a SerializationException will occur. For more information, see Understand the data context passed to a plug-in. Make sure that you do not mix your types and use an early bound type where a late-bound type is called for as shown in the following code.

context.InputParameters["Target"] = new Account() { Name = "MyAccount" }; // WRONG: Do not do this.

In the example above, you do not want to store an early-bound instance in the plug-in context where a late-bound instance should go. This is to avoid requiring the platform to convert between early-bound and late bound types before calling a plug-in and when returning from the plug-in to the platform.

Plug-in Assemblies

There can be one or more plug-in types in an assembly. After the plug-in assembly is registered and deployed, plug-ins can perform their intended operation in response to a Microsoft Dynamics 365 run-time event.

System_CAPS_security Security Note

In Microsoft Dynamics 365, plug-in assemblies must be readable by everyone to work correctly. Therefore, it is a security best practice to develop plug-in code that does not contain any system logon information, confidential information, or company trade secrets.

Each plug-in assembly must be signed, either by using the Signing tab of the project's properties sheet in Microsoft Visual Studio or the Strong Name tool, before being registered and deployed to Microsoft Dynamics 365. For more information about the Strong Name tool, run the sn.exe program, without any arguments, from a Microsoft Visual Studio Command Prompt window.

If your assembly contains a plug-in that can execute while the Dynamics 365 for Outlook is offline, there is additional security that the Microsoft Dynamics 365 platform imposes on assemblies. For more information, see Walkthrough: Configure assembly security for an offline plug-in.

See Also

Plug-in development
Understand the data context passed to a plug-in
Write a custom Azure-aware plug-in
Register and Deploy Plug-Ins
Handle exceptions in plug-ins
Sample: Create a basic plug-in
Sample: Web access from a sandboxed plug-in
Run the code generation tool
Blog: Using Plug-Ins To Modify Views

Microsoft Dynamics 365

© 2016 Microsoft. All rights reserved. Copyright