Tip #731: Hide and protect your custom CRM API

Protect yourself by coveringYesterday we illustrated how you can wrap some server-side functionality as a custom API to be consumed by the developers. One of the undesired side effects is that business can now poke their nose into the API when building workflow processes:

I can see your API in workflow

If your API is a smoking gun and you don’t want business to accidentally set it off then you can hide your API by introducing parameters that would stop custom action from appearing in the Action list. These “business unfriendly” parameter types include Picklist, Entity, or Entity Collection.

Let’s redefine our Normalize Customer action by declaring it to be global but adding a mandatory collection of contacts as a parameter:

Redefine custom action

Metadata definition will now look like:

<Action Name="georged_NormalizeCustomer">
  <Parameter Name="Customer" 

And we have to slightly change our plugin code:

var contacts = localContext.PluginExecutionContext
  .InputParameters["Customers"] as EntityCollection;
foreach (var contactParam in contacts.Entities)
// do your evil stuff

And then change the calling implementation (note that we didn’t have to change the main code, only implementation):

public static class Extensions
  public static void NormalizeCustomer(
       this IOrganizationService service, 
       Guid contactid)
    var request = new OrganizationRequest

//  old stuff	  
//  request.Parameters.Add("Target", 
//    new EntityReference("contact", contactid));

    var contacts = new EntityCollection() 
	{ EntityName = "contact" };
	new Entity("contact", contactid));

    request.Parameters.Add("Customers", contacts);

    var response = service.Execute(request);

Business now is safe:

Action is no longer available

Added bonus of this approach is that our API can now be called for the collection of the contact entities. Think about user selecting multiple records in the web client, and then pressing a button that would invoke a custom javascript sending a single message to the backend with the collection of the selected records. Then the plugin code (a.k.a. API implementation) can process these records in a batch request or transaction. All in a single round-trip.

Leave a Reply

Your email address will not be published. Required fields are marked *