Recently we ran into an issue where a workflow configured to run upon changing a particular field was being triggered even though that field was not being updated. In the end it turned out that this was because of the way we were updating the record via the CRM web service. The lesson learnt was quite interesting and I’d like to share it in this post.

Attribute filtering

As you may be aware, when registering an Update plugin, we can configure the attributes that should trigger the plugin. The meaning of this configuration however is often misunderstood.

Take the screenshot below for example.

The above configuration does not mean that the plugin will be executed only when the Account Number field is changed. Rather, it means that the plugin will be executed only when the Account Number field is present in the incoming update request. If the Account Number field is present in the incoming update request, the plugin will execute, even if its incoming value is the same as the current value in the database.

So what does ‘present in the incoming update request‘ mean?

When you debug an Update plugin, retrieve the Target entity from the InputParameters collection and have a look at its Attributes collection. An attribute is present in the incoming update request if it exists in this collection.

In the screenshot below, you can see that my incoming update request contains name, telephone1, fax, websiteurl, and a few basic fields that are always passed as part of the request.

Wait… what does this have to do with workflow?!

Well, workflow has a similar configuration: it can be started automatically after certain fields have changed.

Our testing has shown that this configuration actually works the same way as plugin’s attribute filtering: the workflow will be triggered if one of the specified fields is present in the incoming update request.

OK… how is this related to updating records via web service?

When you update the record via the CRM’s UI, it is smart enough to only send through the fields that are dirty (i.e. where the value has changed), which means your plugin’s attribute filtering and workflow automatic trigger will function as one would normally expect.

When you update the record by calling the CRM’s web service however, it is up to you to ensure that only dirty fields are being included in the update request.

Even though I only updated the telephone1 field after retrieving the entity, this code will cause all fields to be included in the update request, and essentially defeat the purpose of any plugin attribute filtering or workflow automatic trigger you may have configured.

Below is the record’s audit history after the above update. Notice how it lists other fields as ‘Changed Field’ even though the old and new values are the same?

So how do we fix it?!

The problem with the above code lies in the retrieval of the record (prior to setting the field), specifically the fact that I specified to retrieve all columns using new ColumnSet(true). This causes all fields to be included in the update request, regardless of whether they were touched after the retrieval.

Because you included the telephone1 field in the retrieval, and updated the fax field, both of these will be included in the update request. If you have any plugin or workflow that are triggered on changing of the Telephone field, they will now be executed even though you only meant to update the Fax field.

To address this issue, you would need to remove the telephone1 field from the entity after reading its value, like below:

var entity = service.Retrieve("account", Guid.Parse("F0A3C092-C076-E411-8111-B86B23AC9F7C"), new ColumnSet("telephone1"));
var telephone = entity.Attributes["telephone1"];
entity.Attributes["fax"] = telephone;
//Remove this field to ensure that it is not included in the update request
entity.Attributes.Remove("telephone1");
service.Update(entity);

Alright… but how about early-binding?!

When using the CRM web service directly, we can control which fields are retrieved. I haven’t come across a way of doing this with early-binding.

The code to update an entity using early-binding typically looks like the below:

The above code will cause all fields to be included in the update request.

There are two options for addressing this in early-binding:

Remove the fields that we are not updating, or

Create a new blank entity and use this to perform the update

Remove the fields that we are not updating

One thing you should know is that the early-binding classes inherit from the Entity class, and therefore still have the Attributes collection. All field values are stored in this collection. This means we could loop through and remove the fields that should not be included in the update request from this collection.

The above option works fine, but can get a bit unwieldy when you need to update many fields. The alternative is to create a new blank entity and perform the update on this entity instead. This works because when you create a new blank entity, the Attributes collection is empty. Fields are added to it as you set the properties of the entity. Be sure to set the ID of the new blank entity though, and you will also need to do some Attach/Detach with the context.

Let say again we need to set the Fax of an account to its Telephone. Below is how you would do it with this approach.

One other thing…

Did you notice that several fields are always included in an update request? These are the ID field (e.g. accountid), modifiedon, modifiedby, modifiedonbehalfby. This means you should always exclude these fields in your plugin attribute filtering.

Conclusion

Misunderstanding plugin/workflow attribute filtering may see your system executing processes when it should not be. Take care when updating records via the CRM web service, as your code plays a vital part in ensuring your plugin/workflow attribute filtering configuration works as intended.

Advertisements

Share this:

Like this:

LikeLoading...

Related

About Bernado

Based in Australia, I am a freelance SharePoint and Dynamics CRM developer. I love developing innovative solutions that address business and everyday problems. Feel free to contact me if you think I can help you with your SharePoint or CRM implementation.