Bypass custom Dataverse logic
There are times when you want to be able to perform data operations without having custom business logic applied in Dataverse. These scenarios typically involve bulk data operations where large numbers of records are being created, updated, or deleted.
Without a way to tell Dataverse not to invoke the business logic, you need to locate and disable the individual custom plug-ins and workflows that contain the business logic. Disabling plug-ins and workflows means that the logic is disabled for all users while those plug-ins and workflows are disabled. It also means that you have to take care to only disable the right plug-ins and workflows and remember to re-enable them when you're done.
Instead of this manual process, as a developer of a client application or plug-in, you can pass special optional parameters with your requests to control two types of custom business logic as described in the following table:
Logic type | When to bypass |
---|---|
Synchronous Logic | To enable bulk data operation to be completed as quickly as possible. Bypass synchronous logic when the data you're changing is known to meet the requirements of the organization, or you have a plan to achieve this logic by other means. Bypass all custom synchronous logic so that each operation can complete faster, shortening the total time of the bulk operation. |
Asynchronous Logic | When large numbers of system jobs created to process asynchronous logic cause a backup within Dataverse that can affect performance. You can mitigate this performance issue by not triggering the asynchronous logic while performing bulk operations. |
Note
Power Automate flows represent another type of asynchronous logic that can be managed separately. See Bypass Power Automate Flows
Use these optional parameters to control business logic executed in Dataverse:
Optional parameter | Description |
---|---|
BypassBusinessLogicExecution |
Pass the values CustomSync , CustomAsync , or CustomSync,CustomAsync to this optional parameter to bypass synchronous logic, asynchronous logic or, both. |
BypassBusinessLogicExecutionStepIds |
Pass a comma separated list of plug-in step registrations to bypass only the specified plug-in steps. |
BypassCustomPluginExecution |
Bypass only synchronous logic. This optional parameter is supported, but not recommended. Use BypassBusinessLogicExecution with the CustomSync value to get the same result. |
The BypassBusinessLogicExecution
optional parameter works similarly to the BypassCustomPluginExecution
optional parameter except that you can choose whether to bypass synchronous logic, asynchronous logic or, both.
This optional parameter targets the custom business logic applied for your organization. When you send requests that bypass custom business logic, all custom plug-ins and workflows are disabled except:
- Plug-ins that are part of the core Microsoft Dataverse system or part of a solution where Microsoft is the publisher.
- Workflows included in a solution where Microsoft is the publisher.
System plug-ins define the core behaviors for specific entities. Without these plug-ins, you would encounter data inconsistencies that might not be easily fixed.
Solutions shipped by Microsoft that use Dataverse such as Microsoft Dynamics 365 Customer Service, or Dynamics 365 Sales also include critical business logic that can't be bypassed with this option.
Important
You may have purchased and installed solutions from other Independent Software Vendors (ISVs) which include their own business logic. The logic applied by these solutions will be bypassed. You should check with these ISVs before you use this option to understand what impact there may be if you use this option with data that their solutions use.
The following table describes when to use the parameter values with BypassBusinessLogicExecution
.
Parameter | Description |
---|---|
CustomSync |
Bypass only synchronous custom logic. The compute time necessary for synchronous logic accrues to the total time required to perform each data operation. Use this option to reduce the amount of time required to complete operations in bulk. |
CustomAsync |
Bypass only asynchronous custom logic, excluding Power Automate Flows. Dataverse applies asynchronous logic after an operation completes. When a large number of operations trigger asynchronous logic, Dataverse requires more resources to process the custom logic and this resource consumption can affect performance. Use this option to avoid general performance issues that might occur when large numbers of operations trigger asynchronous logic. |
CustomSync,CustomAsync |
Bypass both synchronous and asynchronous custom logic, excluding Power Automate Flows. |
- You must send the requests using the
BypassBusinessLogicExecution
optional parameter. - The user sending the requests must have the
prvBypassCustomBusinessLogic
privilege. By default, only users with the system administrator security role have this privilege. Learn how to add the theprvBypassCustomBusinessLogic
privilege to another role
You can use this option with either the SDK for .NET or the Web API.
The following example sets the BypassBusinessLogicExecution
optional parameter for both synchronous and asynchronous custom logic when creating a new account record using the SDK for .NET CreateRequest class.
static void DemonstrateBypassBusinessLogicExecution(IOrganizationService service)
{
Entity account = new("account");
account["name"] = "Sample Account";
CreateRequest request = new()
{
Target = account
};
request.Parameters.Add("BypassBusinessLogicExecution", "CustomSync,CustomAsync");
service.Execute(request);
}
Use the BypassBusinessLogicExecutionStepIds
optional parameter to bypass specified registered plug-in steps instead of all synchronous and asynchronous custom logic. Pass the GUID values of the registered plug-in step registrations with this parameter. If the step ID passed doesn't run in the given request, it's ignored.
You can use this option with either the SDK for .NET or the Web API.
The following example sets the optional BypassBusinessLogicExecutionStepIds
parameter when creating a new account record using the CreateRequest class.
static void DemonstrateBypassBusinessLogicExecutionStepIds(IOrganizationService service)
{
Entity account = new("account");
account["name"] = "Sample Account";
CreateRequest request = new()
{
Target = account
};
request.Parameters.Add("BypassBusinessLogicExecutionStepIds", "45e0c603-0d0b-466e-a286-d7fc1cda8361,d5370603-e4b9-4b92-b765-5966492a4fd7");
service.Execute(request);
}
There are a couple of ways to locate the GUID values of the plug-in step registration.
From the View menu, select Display by Entity.
Select the entity and message
Select the step.
In the detail pane, the Properties tab shows the StepId. Copy the value from there.
Learn more about the Plug-in registration tool
Use a query like the following to retrieve the set plug-in step registrations for a given table and message. The following example specifies the account
table, using the table logical name. Create
is the name of the message. Replace these values with the table and message you need.
Request
GET [Organization URI]/api/data/v9.2/sdkmessagefilters?$select=sdkmessagefilterid
&$filter=primaryobjecttypecode eq 'account'
and sdkmessageid/name eq 'Create'
&$expand=sdkmessagefilterid_sdkmessageprocessingstep($select=name;
$filter=statecode eq 0
and customizationlevel eq 1
and iscustomizable/Value eq true)
Accept: application/json
OData-MaxVersion: 4.0
OData-Version: 4.0
Response
In the response, look for the sdkmessageprocessingstepid
values. Use the name
value to identify the plug-in that you want to bypass.
In this case, there's only one: 4ab978b0-1d77-ec11-8d21-000d3a554d57
{
"@odata.context": "[Organization URI]/api/data/v9.2/$metadata#sdkmessagefilters(sdkmessagefilterid,sdkmessagefilterid_sdkmessageprocessingstep(name))",
"value": [
{
"@odata.etag": "W/\"31434372\"",
"sdkmessagefilterid": "c2c5bb1b-ea3e-db11-86a7-000a3a5473e8",
"sdkmessagefilterid_sdkmessageprocessingstep": [
{
"@odata.etag": "W/\"115803276\"",
"name": "BasicPlugin.FollowupPlugin: Create of account",
"_sdkmessagefilterid_value": "c2c5bb1b-ea3e-db11-86a7-000a3a5473e8",
"sdkmessageprocessingstepid": "4ab978b0-1d77-ec11-8d21-000d3a554d57"
}
],
"sdkmessagefilterid_sdkmessageprocessingstep@odata.nextLink": "[Organization URI]/api/data/v9.2/sdkmessagefilters(c2c5bb1b-ea3e-db11-86a7-000a3a5473e8)/sdkmessagefilterid_sdkmessageprocessingstep?$select=name&$filter=statecode%20eq%200%20and%20customizationlevel%20eq%201%20and%20iscustomizable/Value%20eq%20true"
}
]
}
Learn more about querying data using Web API
Use a query like the following to retrieve the set plug-in step registrations for a given table and message. The following example specifies 1
to represent the account
table, using the table object type code.
Note
For tables where the object type code is over 10000
, the value will not be the same in every environment because this value is assigned an incrementing value when the table is created.
If you know the logical name of the table, you can get the object type code using a Web API request. This request returns the value 1
, the object type code for the account
table.
GET [Organization URI]/api/data/v9.2/EntityDefinitions(LogicalName='account')/ObjectTypeCode/$value
Create
is the name of the message. Replace these values with the table and message you need.
Use this FetchXml query to return step.sdkmessageprocessingstepid
values you can use with the BypassBusinessLogicExecutionStepIds
optional parameter.
<fetch>
<entity name='sdkmessagefilter'>
<filter>
<condition attribute='primaryobjecttypecode'
operator='eq'
value='1' />
</filter>
<link-entity name='sdkmessage'
from='sdkmessageid'
to='sdkmessageid'
link-type='inner'
alias='message'>
<filter>
<condition attribute='name'
operator='eq'
value='Create' />
</filter>
</link-entity>
<link-entity name='sdkmessageprocessingstep'
from='sdkmessagefilterid'
to='sdkmessagefilterid'
link-type='inner'
alias='step'>
<attribute name='name' />
<filter>
<condition attribute='statecode'
operator='eq'
value='0' />
<condition attribute='customizationlevel'
operator='eq'
value='1' />
<condition attribute='iscustomizable'
operator='eq'
value='1' />
</filter>
</link-entity>
</entity>
</fetch>
Learn more about retrieving data using FetchXml
To ensure that the parameter size isn't too large, the default limit on the number of steps you can pass is three. The limit is controlled using data in the Organization table OrgDbOrgSettings column. Use the OrgDBOrgSettings tool for Microsoft Dynamics CRM or OrgDbOrgSettings app to change the BypassBusinessLogicExecutionStepIdsLimit
value.
The maximum recommended size for this limit is 10 steps.
Use the BypassCustomPluginExecution
optional parameter to bypass custom synchronous logic.
Note
This was the first optional parameter that allowed limiting business logic. It remains supported, but we recommend using BypassBusinessLogicExecution
with the CustomSync
value to get the same result.
Use this optional parameter in the same way you use BypassBusinessLogicExecution
, except it requires a different privilege: prvBypassCustomPlugins
You can use this option with either the SDK for .NET or the Web API.
There are two ways to use this optional parameter with the SDK for .NET.
The following example sets the optional BypassCustomPluginExecution
parameter when creating a new account record using the CreateRequest class.
static void DemonstrateBypassCustomPluginExecution(IOrganizationService service)
{
Entity account = new("account");
account["name"] = "Sample Account";
CreateRequest request = new()
{
Target = account
};
request.Parameters.Add("BypassCustomPluginExecution", true);
service.Execute(request);
}
You can use this method for data operations you initiate in your plug-ins when the calling user has the prvBypassCustomPlugins
privilege.
The following example sets the CrmServiceClient.BypassPluginExecution Property when creating a new account record:
var service = new CrmServiceClient(connectionString);
service.BypassPluginExecution = true;
var account = new Entity("account");
account["name"] = "Sample Account";
service.Create(account);
Because this setting is applied to the service, it remains set for all requests sent using the service until it's set to false
.
Note
This property is not available in the Dataverse.Client.ServiceClient, but it is available on the Dataverse.Client.Extensions.CRUDExtentions methods.
The optional parameters described in this article require privileges that are only added to the system administrator security role. These privileges aren't available in the security role designer to add to other security roles. If you need to grant this privilege to another security role, you must use the API. For example, you might want to grant this privilege to a user with the system customizer security role.
To add the privilege to another security role, you need the ID of the privilege.
Name | ID | Optional Parameter(s) |
---|---|---|
prvBypassCustomBusinessLogic |
0ea552b0-a491-4470-9a1b-82068deccf66 |
BypassBusinessLogicExecution BypassBusinessLogicExecutionStepIds |
prvBypassCustomPlugins |
148a9eaf-d0c4-4196-9852-c3a38e35f6a1 |
BypassCustomPluginExecution |
These ID values are the same for all Dataverse environments.
Associate the prvBypassCustomBusinessLogic
privilege to a security role using AddPrivilegesRoleRequest.
static void AddprvBypassCustomPluginsToRole(IOrganizationService service, Guid roleId)
{
var request = new AddPrivilegesRoleRequest
{
RoleId = roleId,
Privileges = new[]{
new RolePrivilege{
PrivilegeId = new Guid("0ea552b0-a491-4470-9a1b-82068deccf66"),
Depth = PrivilegeDepth.Global
}
}
};
service.Execute(request);
}
Following are frequently asked questions about using the optional parameters to bypass synchronous business logic.
No. If a plug-in or workflow in a Microsoft solution performs operations on other records, the logic for those operations aren't bypassed. Only those plugins or workflows that apply to the specific operation are bypassed.
Yes, but only when the plug-in is running in the context of a user who has the required privilege. For plug-ins, set the optional parameter on the class derived from OrganizationRequest Class. You can't use the CrmServiceClient or ServiceClient classes in a plug-in.