Sometimes you write applications that contains some logic, that require you to create steps for your plugin based on other entities. For example, if you have an AutoNumber solution, you can create a plugin step for a particular entity every time you create a new AutoNumber record.
This process will allow your AutoNumber functionality to be immediately available when the user creates a new AutoNumber Settings record.
In order to do this, you will need to either retrieve or hard code the name of your assembly and plugin type as shown below.
const string ASSEMBLY_NAME = "Dyn365.Xrm.Plugins.AutoNumber"; const string PLUGIN_TYPE_NAME = "Dyn365.Xrm.Plugins.AutoNumber.PluginEntryPoint";
We then need to get the Guid of the message that we are adding, as well as get the Object Type Code and check if this message already exists, so that we bypass this logic if there is already a step for this message.
public void PublishSDKMessageProcessingStep(string entityName, Guid impersonatingUserId) { Guid sdkMessageId = GetSdkMessageId("Create"); int? objectTypeCode = RetrieveEntityMetadataObjectTypeCode(entityName.ToLower()); if (objectTypeCode.HasValue) { bool stepExists = RetrieveSdkMessageProcessingStep(sdkMessageId, objectTypeCode.Value); if (!stepExists) CreateSdkMessageProcessingStep(string.Format("{0}: Create of {1}", PLUGIN_TYPE_NAME, entityName), entityName.ToLower(), "", StepMode.Sync, 10, PluginStage.PostOperation, StepInvocationSource.Parent, impersonatingUserId); } }
private int? RetrieveEntityMetadataObjectTypeCode(string entityName) { RetrieveEntityRequest request = new RetrieveEntityRequest() { EntityFilters = EntityFilters.Entity, LogicalName = entityName }; RetrieveEntityResponse response = (RetrieveEntityResponse)service.Execute(request); int? result = response.EntityMetadata.ObjectTypeCode; return result; }
The RetrieveSdkMessageProcessingStep is a queryexpression on the SdkMessageProcessingStep with multiple linked entities (SdkMessageFilter and PluginType) to check if the record already exists. It is probably easiest to do this as a FetchXml query, but works both ways. The CreateSdkMessageProcessingStep function was called after the retrieval of the required values. This method will create the SDKMessageProcessingStep record. We will need to get the Ids of some of the Plugin types in order to complete the save operation
private Guid CreateSdkMessageProcessingStep(string name, string entityName, string configuration, StepMode mode, int rank, PluginStage stage, StepInvocationSource invocationSource, Guid impersonatingUserId) { Entity step = new Entity("sdkmessageprocessingstep"); step["name"] = name; step["description"] = name; step["configuration"] = configuration; step["mode"] = new OptionSetValue(mode.ToInt()); step["rank"] = rank; step["stage"] = new OptionSetValue(stage.ToInt()); step["supporteddeployment"] = new OptionSetValue(0); // Server Only step["invocationsource"] = new OptionSetValue(invocationSource.ToInt()); Guid sdkMessageId = GetSdkMessageId("Create"); Guid sdkMessageFilterId = GetSdkMessageFilterId(entityName, sdkMessageId); Guid assemblyId = GetPluginAssemblyId(ASSEMBLY_NAME); Guid pluginTypeId = GetPluginTypeId(assemblyId, PLUGIN_TYPE_NAME); step["plugintypeid"] = new EntityReference("plugintype", pluginTypeId); step["sdkmessageid"] = new EntityReference("sdkmessage", sdkMessageId); step["sdkmessagefilterid"] = new EntityReference("sdkmessagefilter", sdkMessageFilterId); if (impersonatingUserId != Guid.Empty) step["impersonatinguserid"] = new EntityReference("systemuser", impersonatingUserId); try { Guid stepId = service.Create(step); return stepId; } catch (InvalidPluginExecutionException invalidPluginExecutionException) { throw invalidPluginExecutionException; } catch (Exception exception) { throw exception; } }
private Guid GetSdkMessageId(string SdkMessageName) { try { //GET SDK MESSAGE QUERY QueryExpression sdkMessageQueryExpression = new QueryExpression("sdkmessage"); sdkMessageQueryExpression.ColumnSet = new ColumnSet("sdkmessageid"); sdkMessageQueryExpression.Criteria = new FilterExpression { Conditions = { new ConditionExpression { AttributeName = "name", Operator = ConditionOperator.Equal, Values = {SdkMessageName} }, } }; //RETRIEVE SDK MESSAGE EntityCollection sdkMessages = service.RetrieveMultiple(sdkMessageQueryExpression); if (sdkMessages.Entities.Count != 0) { return sdkMessages.Entities.First().Id; } throw new Exception(String.Format("SDK MessageName {0} was not found.", SdkMessageName)); } catch (InvalidPluginExecutionException invalidPluginExecutionException) { throw invalidPluginExecutionException; } catch (Exception exception) { throw exception; } }
private Guid GetSdkMessageFilterId(string EntityLogicalName, Guid sdkMessageId) { try { //GET SDK MESSAGE FILTER QUERY QueryExpression sdkMessageFilterQueryExpression = new QueryExpression("sdkmessagefilter"); sdkMessageFilterQueryExpression.ColumnSet = new ColumnSet("sdkmessagefilterid"); sdkMessageFilterQueryExpression.Criteria = new FilterExpression { Conditions = { new ConditionExpression { AttributeName = "primaryobjecttypecode", Operator = ConditionOperator.Equal, Values = {EntityLogicalName} }, new ConditionExpression { AttributeName = "sdkmessageid", Operator = ConditionOperator.Equal, Values = {sdkMessageId} }, } }; //RETRIEVE SDK MESSAGE FILTER EntityCollection sdkMessageFilters = service.RetrieveMultiple(sdkMessageFilterQueryExpression); if (sdkMessageFilters.Entities.Count != 0) { return sdkMessageFilters.Entities.First().Id; } throw new Exception(String.Format("SDK Message Filter for {0} was not found.", EntityLogicalName)); } catch (InvalidPluginExecutionException invalidPluginExecutionException) { throw invalidPluginExecutionException; } catch (Exception exception) { throw exception; } }
private Guid GetPluginAssemblyId(string assemblyName) { try { //GET ASSEMBLY QUERY QueryExpression pluginAssemblyQueryExpression = new QueryExpression("pluginassembly"); pluginAssemblyQueryExpression.ColumnSet = new ColumnSet("pluginassemblyid"); pluginAssemblyQueryExpression.Criteria = new FilterExpression { Conditions = { new ConditionExpression { AttributeName = "name", Operator = ConditionOperator.Equal, Values = {assemblyName} }, } }; //RETRIEVE ASSEMBLY EntityCollection pluginAssemblies = service.RetrieveMultiple(pluginAssemblyQueryExpression); Guid assemblyId = Guid.Empty; if (pluginAssemblies.Entities.Count != 0) { //ASSIGN ASSEMBLY ID TO VARIABLE assemblyId = pluginAssemblies.Entities.First().Id; } return assemblyId; } catch (InvalidPluginExecutionException invalidPluginExecutionException) { throw invalidPluginExecutionException; } catch (Exception exception) { throw exception; } }
private Guid GetPluginTypeId(Guid assemblyId, string PluginTypeName) { try { //GET PLUGIN TYPES WITHIN ASSEMBLY QueryExpression pluginTypeQueryExpression = new QueryExpression("plugintype"); pluginTypeQueryExpression.ColumnSet = new ColumnSet("plugintypeid"); pluginTypeQueryExpression.Criteria = new FilterExpression { Conditions = { new ConditionExpression { AttributeName = "pluginassemblyid", Operator = ConditionOperator.Equal, Values = {assemblyId} }, new ConditionExpression { AttributeName = "typename", Operator = ConditionOperator.Equal, Values = {PluginTypeName} }, } }; //RETRIEVE PLUGIN TYPES IN ASSEMBLY EntityCollection pluginTypes = service.RetrieveMultiple(pluginTypeQueryExpression); //RETURN PLUGIN TYPE ID if (pluginTypes.Entities.Count != 0) { return pluginTypes.Entities.First().Id; } throw new Exception(String.Format("Plugin Type {0} was not found in Assembly", PluginTypeName)); } catch (InvalidPluginExecutionException invalidPluginExecutionException) { throw invalidPluginExecutionException; } catch (Exception exception) { throw exception; } }
As you can see, the process is pretty simple, but requires a lot of trips to get the unique identifier values of the Assembly, Plugin Type, Plugin and Message Id, and Message Filter Id.