Dataverse: Four Ways to Bypass PluginExecution in CrmServiceClient

There is always a scenario in your organization that requires you to bypass PluginExecution (can be workflows or plugins) when doing CRUD (Create, Read, Update, or Delete) operations. Today, we will learn how we can do it in several ways.

For this demonstration, I create a Workflow that will be running on Contact when Created:

Create Workflow For Contact on Create

The process is simple: if we create a Contact, we will update Address 1 as “UPDATE BY WORKFLOW”. You can get the WorkflowId by copying the red square in the picture above (you will need it for the next step).

Then I also created a simple plugin with the below code:

using Microsoft.Xrm.Sdk;
using System;

namespace DemoPlugin
{
    public class Plugin1 : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            var context = (IPluginExecutionContext)
                serviceProvider.GetService(typeof(IPluginExecutionContext));

            if (context.SharedVariables.ContainsKey("tag") &&
                bool.Parse(context.SharedVariables["tag"].ToString()))
            {
                return;
            }

            var target = context.InputParameters["Target"] as Entity;
            if (target == null) return;

            target["address3_composite"] = "From Plugin";
        }
    }
}

Once it is done, I register the plugin and make a plugin step like below:

Register Plugin+Plugin Step

To get the plugin step id, you just need to go to the properties tab of the plugin step and copy the StepId:

Get The Plugin StepId

With all the setup is done, we can go to the main things we are here today. Below are several steps that we can do to bypass the plugin execution!

CrmServiceClient.BypassPluginExecution

Below is the code to bypass the PluginExecution utilizing CrmServiceClient.BypassPluginExecution (Every action that you run in this instance will bypass the PluginExecution):

var connectionString = WebConfigurationManager.AppSettings["connectionString"];
var client = new CrmServiceClient(connectionString);
// Will by pass plugin execution
client.BypassPluginExecution = true;

var entity1 = new Entity("contact");
entity1["firstname"] = "Temmy";
entity1["lastname"] = "1";
var id1 = client.Create(entity1);
Console.WriteLine($"Created with id1: " + id1);

Enable/Disabled Workflow/Plugin By Code

The next step is to enable/disable the workflow/plugin step that we want by using the code:

var client1 = new CrmServiceClient(connectionString);

EnableDisabledWorkflow(client, true);

var entity3 = new Entity("contact");
entity3["firstname"] = "Temmy";
entity3["lastname"] = "3";
var id3 = client.Create(entity3);
Console.WriteLine($"Created with id3: " + id3);

EnableDisabledWorkflow(client, false);

Below is the code for the EnableDisabledWorkflow method (WorkflowId/PluginStepId based on the previous steps):

public static void EnableDisabledWorkflow(IOrganizationService service, bool disabled)
{
	var setStateRequest = new SetStateRequest
	{
		EntityMoniker = new EntityReference("workflow", 
			new Guid("2A741E07-AC7B-4228-8067-A4F04AD50CB0")),
		State = new OptionSetValue(disabled ? 0 : 1), // 1 Activated, 0 Draft
		Status = new OptionSetValue(disabled ? 1 : 2), // 2 Activated, 1 Draft
	};
	service.Execute(setStateRequest);

	var setStateRequest1 = new SetStateRequest
	{
		EntityMoniker = new EntityReference("sdkmessageprocessingstep", 
		new Guid("6079bde5-d37a-ec11-8d21-0022485a8e02")),
		State = new OptionSetValue(disabled ? 1 : 0), // 1 Disabled, 0 Enabled
		Status = new OptionSetValue(disabled ? 2 : 1), // 2 Disabled, 1 Enabled
	};
	service.Execute(setStateRequest1);

	Console.WriteLine($"{(disabled ? "Disabled" : "Enabled")} workflow and plugin step..");
}

This method will be more dynamic because you can control which plugin step/workflow we want to bypass. But unfortunately, it will affect all the users in the system as well. That is why this method will only be used if your system is not being used for 24 hours.

Using BypassCustomPluginExecution for CreateRequest/UpdateRequest/DeleteRequest

You can utilize the BypassCustomPluginExecution attribute to bypass PluginExecution when you doing a specific request:

var client1 = new CrmServiceClient(connectionString);

var entity4 = new Entity("contact");
entity4["firstname"] = "Temmy";
entity4["lastname"] = "4";

var createReq = new CreateRequest { Target = entity3, ["BypassCustomPluginExecution"] = true };
var result = (CreateResponse)client1.Execute(createReq);
Console.WriteLine($"Created with id4: " + result.id);

Remember, you only can use this method using CrmServiceClient.Execute method (can’t in CrmServiceClient.Create/Update/Delete).

Using Tag for CreateRequest/UpdateRequest/DeleteRequest

Not so long after I post this blog post, The OG, Tanguy TOUZARD let me know there is another way to bypass the plugin based on this blog post by Bipin Kumar. So here is another way to do it:

var client1 = new CrmServiceClient(connectionString);

var entity5 = new Entity("contact");
entity5["firstname"] = "Temmy";
entity5["lastname"] = "5";

var createReq1 = new CreateRequest { Target = entity5, ["tag"] = true };
var result2 = (CreateResponse)client1.Execute(createReq1);
Console.WriteLine($"Created with id5: " + result2.id);

You can only pass the “tag” parameter. Else you will get an error to indicate that the parameter that you pass does not exist.

Summary

The full source code:

using System;
using System.Web.Configuration;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Tooling.Connector;

namespace CrmCheck
{
    class Program
    {
        static void Main(string[] args)
        {
            var connectionString = WebConfigurationManager.AppSettings["connectionString"];
            var client = new CrmServiceClient(connectionString);
            //// Will by pass plugin execution
            client.BypassPluginExecution = true;

            var entity1 = new Entity("contact");
            entity1["firstname"] = "Temmy";
            entity1["lastname"] = "1";
            var id1 = client.Create(entity1);
            Console.WriteLine($"Created with id1: " + id1);

            // Normal service client
            var client1 = new CrmServiceClient(connectionString);
            var entity2 = new Entity("contact");
            entity2["firstname"] = "Temmy";
            entity2["lastname"] = "2";

            var id2 = client1.Create(entity2);
            Console.WriteLine($"Created with id2: " + id2);

            EnableDisabledWorkflow(client, true);

            var entity3 = new Entity("contact");
            entity3["firstname"] = "Temmy";
            entity3["lastname"] = "3";
            var id3 = client.Create(entity3);
            Console.WriteLine($"Created with id3: " + id3);

            EnableDisabledWorkflow(client, false);

            var entity4 = new Entity("contact");
            entity4["firstname"] = "Temmy";
            entity4["lastname"] = "4";

            var createReq = new CreateRequest { Target = entity4, ["BypassCustomPluginExecution"] = true };
            var result = (CreateResponse)client1.Execute(createReq);
            Console.WriteLine($"Created with id4: " + result.id);

            var entity5 = new Entity("contact");
            entity5["firstname"] = "Temmy";
            entity5["lastname"] = "5";

            var createReq1 = new CreateRequest { Target = entity5, ["tag"] = true };
            var result2 = (CreateResponse)client1.Execute(createReq1);
            Console.WriteLine($"Created with id5: " + result2.id);

            Console.ReadKey();
        }

        public static void EnableDisabledWorkflow(IOrganizationService service, bool disabled)
        {
            var setStateRequest = new SetStateRequest
            {
                EntityMoniker = new EntityReference("workflow",
                    new Guid("2A741E07-AC7B-4228-8067-A4F04AD50CB0")),
                State = new OptionSetValue(disabled ? 0 : 1), // 1 Activated, 0 Draft
                Status = new OptionSetValue(disabled ? 1 : 2), // 2 Activated, 1 Draft
            };
            service.Execute(setStateRequest);

            var setStateRequest1 = new SetStateRequest
            {
                EntityMoniker = new EntityReference("sdkmessageprocessingstep",
                new Guid("6079bde5-d37a-ec11-8d21-0022485a8e02")),
                State = new OptionSetValue(disabled ? 1 : 0), // 1 Disabled, 0 Enabled
                Status = new OptionSetValue(disabled ? 2 : 1), // 2 Disabled, 1 Enabled
            };
            service.Execute(setStateRequest1);

            Console.WriteLine($"{(disabled ? "Disabled" : "Enabled")} workflow and plugin step..");
        }
    }
}

Ther Result:

The Result

Happy CRM-ing!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.