Beispiel #1
0
        internal MockupService(Core core, Guid?userId, PluginContext pluginContext, MockupServiceSettings settings)
        {
            this.core          = core;
            this.pluginContext = pluginContext;
            if (userId.HasValue && userId.Value != Guid.Empty)
            {
                if (!core.ContainsEntity(new Entity(LogicalNames.SystemUser)
                {
                    Id = userId.Value
                }))
                {
                    throw new FaultException($"The userId '{userId.Value}' does not match a valid user");
                }

                userRef = new EntityReference("systemuser", userId.Value);
            }
            this.settings = settings;
        }
Beispiel #2
0
        public void TriggerSystem(string operation, ExecutionStage stage,
                                  object entity, Entity preImage, Entity postImage, PluginContext pluginContext, Core core)
        {
            if (!this.registeredSystemPlugins.ContainsKey(operation))
            {
                return;
            }
            if (!this.registeredSystemPlugins[operation].ContainsKey(stage))
            {
                return;
            }

            var toExecute = registeredSystemPlugins[operation][stage].Where(p => p.ShouldExecute(entity, preImage, postImage, pluginContext));

            foreach (var plugin in toExecute)
            {
                plugin.Execute(entity, preImage, postImage, pluginContext, core);
            }
        }
        internal void ExecuteWaitingWorkflows(PluginContext pluginContext, Core core)
        {
            var provider = new MockupServiceProviderAndFactory(core, pluginContext, new TracingService());
            var service  = provider.CreateOrganizationService(null, new MockupServiceSettings(true, true, MockupServiceSettings.Role.SDK));

            foreach (var waitInfo in waitingWorkflows.ToList())
            {
                waitingWorkflows.Remove(waitInfo);
                var variables     = waitInfo.VariablesInstance;
                var shadowService = core.ServiceFactory.CreateAdminOrganizationService(new MockupServiceSettings(false, true, MockupServiceSettings.Role.SDK));

                var primaryEntity = shadowService.Retrieve(waitInfo.PrimaryEntity.LogicalName, waitInfo.PrimaryEntity.Id, new ColumnSet(true));
                variables["InputEntities(\"primaryEntity\")"] = primaryEntity;
                waitInfo.Element.Execute(waitInfo.ElementIndex, ref variables, core.TimeOffset, service, provider, new TracingService(), false);
                if (variables["Wait"] != null)
                {
                    waitingWorkflows.Add(variables["Wait"] as WaitInfo);
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Trigger all plugin steps which match the given parameters.
        /// </summary>
        /// <param name="operation"></param>
        /// <param name="stage"></param>
        /// <param name="entity"></param>
        /// <param name="preImage"></param>
        /// <param name="postImage"></param>
        /// <param name="pluginContext"></param>
        /// <param name="core"></param>
        public void Trigger(string operation, ExecutionStage stage,
                            object entity, Entity preImage, Entity postImage, PluginContext pluginContext, Core core)
        {
            if (!disableRegisteredPlugins && registeredPlugins.ContainsKey(operation) && registeredPlugins[operation].ContainsKey(stage))
            {
                var toExecute = registeredPlugins[operation][stage].Where(p => p.ShouldExecute(entity, preImage, postImage, pluginContext));
                foreach (var plugin in toExecute)
                {
                    plugin.Execute(entity, preImage, postImage, pluginContext, core);
                }
            }

            if (temporaryPlugins.ContainsKey(operation) && temporaryPlugins[operation].ContainsKey(stage))
            {
                var toExecute = temporaryPlugins[operation][stage].Where(p => p.ShouldExecute(entity, preImage, postImage, pluginContext));
                foreach (var plugin in toExecute)
                {
                    plugin.Execute(entity, preImage, postImage, pluginContext, core);
                }
            }
        }
        private void Execute(Entity workflow, string operation, object entityObject, Entity preImage, Entity postImage, PluginContext pluginContext, Core core)
        {
            // Check if it is supposed to execute. Returns preemptively, if it should not.
            var entity    = entityObject as Entity;
            var entityRef = entityObject as EntityReference;

            var guid        = entity?.Id ?? entityRef.Id;
            var logicalName = entity?.LogicalName ?? entityRef.LogicalName;

            checkInfiniteRecursion(pluginContext);

            var isCreate = operation.ToLower() == EventOperationStrings.Create;
            var isUpdate = operation.ToLower() == EventOperationStrings.Update;
            var isDelete = operation.ToLower() == EventOperationStrings.Delete;


            var triggerFields = new HashSet <string>();

            if (workflow.GetAttributeValue <string>("triggeronupdateattributelist") != null)
            {
                foreach (var field in workflow.GetAttributeValue <string>("triggeronupdateattributelist").Split(','))
                {
                    triggerFields.Add(field);
                }
            }


            var thisStage = isCreate ? workflow.GetOptionSetValue <workflow_stage>("createstage") :
                            (isDelete ? workflow.GetOptionSetValue <workflow_stage>("deletestage") : workflow.GetOptionSetValue <workflow_stage>("updatestage"));

            if (thisStage == null)
            {
                thisStage = workflow_stage.Postoperation;
            }


            var thisPluginContext = createPluginContext(pluginContext, workflow, thisStage, guid, logicalName);

            var parsedWorkflow = ParseWorkflow(workflow);

            WorkflowTree postExecution = null;

            if (thisStage == workflow_stage.Preoperation)
            {
                postExecution = ExecuteWorkflow(parsedWorkflow, preImage.CloneEntity(), thisPluginContext, core);
            }
            else
            {
                postExecution = ExecuteWorkflow(parsedWorkflow, postImage.CloneEntity(), thisPluginContext, core);
            }

            if (postExecution.Variables["Wait"] != null)
            {
                waitingWorkflows.Add(postExecution.Variables["Wait"] as WaitInfo);
            }
        }
Beispiel #6
0
        internal OrganizationResponse Execute(OrganizationRequest request, EntityReference userRef, PluginContext parentPluginContext)
        {
            // Setup
            HandleInternalPreOperations(request, userRef);

            var primaryRef = Mappings.GetPrimaryEntityReferenceFromRequest(request);

            // Create the plugin context
            var pluginContext = new PluginContext()
            {
                UserId            = userRef.Id,
                InitiatingUserId  = userRef.Id,
                MessageName       = RequestNameToMessageName(request.RequestName),
                Depth             = 1,
                OrganizationName  = this.OrganizationName,
                OrganizationId    = this.OrganizationId,
                PrimaryEntityName = primaryRef?.LogicalName,
            };

            if (primaryRef != null)
            {
                var refEntity = db.GetEntityOrNull(primaryRef);
                pluginContext.PrimaryEntityId = refEntity == null ? Guid.Empty : refEntity.Id;
            }

            foreach (var prop in request.Parameters)
            {
                pluginContext.InputParameters[prop.Key] = prop.Value;
            }
            if (parentPluginContext != null)
            {
                pluginContext.ParentContext = parentPluginContext;
                pluginContext.Depth         = parentPluginContext.Depth + 1;
            }
            var buRef = GetBusinessUnit(userRef);

            pluginContext.BusinessUnitId = buRef.Id;

            Mappings.RequestToEventOperation.TryGetValue(request.GetType(), out string eventOp);
            if (string.IsNullOrEmpty(eventOp))
            {
                //then this may be a custom action request, so continue with the request name
                if (request.RequestName.Contains("_")) //if we have a prefix then assume it is a custom action
                {
                    eventOp = request.RequestName.ToLower();
                }
            }


            var entityInfo = GetEntityInfo(request);

            var settings = MockupExecutionContext.GetSettings(request);

            // Validation
            if (!settings.SetUnsettableFields && (request is UpdateRequest || request is CreateRequest))
            {
                var entity = request is UpdateRequest ? (request as UpdateRequest).Target : (request as CreateRequest).Target;
                Utility.RemoveUnsettableAttributes(request.RequestName, metadata.EntityMetadata.GetMetadata(entity.LogicalName), entity);
            }

            Entity preImage  = null;
            Entity postImage = null;

            if (settings.TriggerProcesses && entityInfo != null)
            {
                preImage = TryRetrieve(primaryRef);
                if (preImage != null)
                {
                    primaryRef.Id = preImage.Id;
                }
            }

            if (settings.TriggerProcesses && entityInfo != null && !string.IsNullOrEmpty(eventOp))
            {
                // System Pre-validation
                pluginManager.TriggerSystem(eventOp, ExecutionStage.PreValidation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                // Pre-validation
                pluginManager.Trigger(eventOp, ExecutionStage.PreValidation, entityInfo.Item1, preImage, postImage, pluginContext, this);

                // Shared variables should be moved to parent context when transitioning from 10 to 20.
                pluginContext.ParentContext = pluginContext.Clone();
                pluginContext.SharedVariables.Clear();

                // Pre-operation
                pluginManager.Trigger(eventOp, ExecutionStage.PreOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                workflowManager.TriggerSync(eventOp, ExecutionStage.PreOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);

                // System Pre-operation
                pluginManager.TriggerSystem(eventOp, ExecutionStage.PreOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
            }

            // Core operation
            OrganizationResponse response = ExecuteRequest(request, userRef, parentPluginContext);

            // Post-operation
            if (settings.TriggerProcesses && entityInfo != null)
            {
                postImage = TryRetrieve(primaryRef);

                // In RetrieveMultipleRequests, the OutputParameters bag contains the entity collection
                if (request is RetrieveMultipleRequest)
                {
                    pluginContext.OutputParameters["BusinessEntityCollection"] = (response as RetrieveMultipleResponse)?.EntityCollection;
                }

                if (!string.IsNullOrEmpty(eventOp))
                {
                    //copy the createon etc system attributes onto the target so they are available for postoperation processing
                    CopySystemAttributes(postImage, entityInfo.Item1 as Entity);

                    pluginManager.TriggerSystem(eventOp, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                    pluginManager.TriggerSync(eventOp, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                    pluginManager.StageAsync(eventOp, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);

                    workflowManager.TriggerSync(eventOp, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                    workflowManager.StageAsync(eventOp, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                }

                //When last Sync has been executed we trigger the Async jobs.
                if (parentPluginContext == null)
                {
                    pluginManager.TriggerAsyncWaitingJobs();
                    workflowManager.TriggerAsync(this);
                }
                workflowManager.ExecuteWaitingWorkflows(pluginContext, this);
            }
            return(response);
        }
Beispiel #7
0
 public void TriggerSync(EventOperation operation, ExecutionStage stage,
                         object entity, Entity preImage, Entity postImage, PluginContext pluginContext, Core core)
 {
     synchronousWorkflows.ForEach((x => ExecuteIfMatch(x, operation, stage, entity,
                                                       preImage, postImage, pluginContext, core)));
 }
Beispiel #8
0
        internal OrganizationResponse Execute(OrganizationRequest request, EntityReference userRef, PluginContext parentPluginContext)
        {
            // Setup
            HandleInternalPreOperations(request, userRef);

            var primaryRef = Mappings.GetPrimaryEntityReferenceFromRequest(request);

            // Create the plugin context
            var pluginContext = new PluginContext()
            {
                UserId            = userRef.Id,
                InitiatingUserId  = userRef.Id,
                MessageName       = RequestNameToMessageName(request.RequestName),
                Depth             = 1,
                OrganizationName  = this.OrganizationName,
                OrganizationId    = this.OrganizationId,
                PrimaryEntityName = primaryRef?.LogicalName,
            };

            if (primaryRef != null)
            {
                var refEntity = db.GetEntityOrNull(primaryRef);
                pluginContext.PrimaryEntityId = refEntity == null ? Guid.Empty : refEntity.Id;
            }

            foreach (var prop in request.Parameters)
            {
                pluginContext.InputParameters[prop.Key] = prop.Value;
            }
            if (parentPluginContext != null)
            {
                pluginContext.ParentContext = parentPluginContext;
                pluginContext.Depth         = parentPluginContext.Depth + 1;
            }
            var buRef = GetBusinessUnit(userRef);

            pluginContext.BusinessUnitId = buRef.Id;

            Mappings.RequestToEventOperation.TryGetValue(request.GetType(), out EventOperation? eventOp);

            var entityInfo = GetEntityInfo(request);

            var settings = MockupExecutionContext.GetSettings(request);

            // Validation
            if (!settings.SetUnsettableFields && (request is UpdateRequest || request is CreateRequest))
            {
                var entity = request is UpdateRequest ? (request as UpdateRequest).Target : (request as CreateRequest).Target;
                Utility.RemoveUnsettableAttributes(request.RequestName, metadata.EntityMetadata.GetMetadata(entity.LogicalName), entity);
            }

            Entity preImage  = null;
            Entity postImage = null;

            if (settings.TriggerProcesses && entityInfo != null)
            {
                preImage = TryRetrieve(primaryRef);
                if (preImage != null)
                {
                    primaryRef.Id = preImage.Id;
                }
            }

            if (settings.TriggerProcesses && entityInfo != null && eventOp.HasValue)
            {
                // System Pre-validation
                pluginManager.TriggerSystem(eventOp.Value, ExecutionStage.PreValidation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                // Pre-validation
                pluginManager.Trigger(eventOp.Value, ExecutionStage.PreValidation, entityInfo.Item1, preImage, postImage, pluginContext, this);

                // Shared variables should be moved to parent context when transitioning from 10 to 20.
                pluginContext.ParentContext = pluginContext.Clone();
                pluginContext.SharedVariables.Clear();

                // Pre-operation
                pluginManager.Trigger(eventOp.Value, ExecutionStage.PreOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                workflowManager.Trigger(eventOp.Value, ExecutionStage.PreOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);

                // System Pre-operation
                pluginManager.TriggerSystem(eventOp.Value, ExecutionStage.PreOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
            }

            // Core operation
            OrganizationResponse response = ExecuteRequest(request, userRef, parentPluginContext);

            // Post-operation
            if (settings.TriggerProcesses && entityInfo != null)
            {
                postImage = TryRetrieve(primaryRef);
                if (eventOp.HasValue)
                {
                    pluginManager.TriggerSystem(eventOp.Value, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                    pluginManager.Trigger(eventOp.Value, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                    workflowManager.Trigger(eventOp.Value, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                }
                workflowManager.ExecuteWaitingWorkflows(pluginContext, this);
            }

            return(response);
        }
Beispiel #9
0
            public void ExecuteIfMatch(object entityObject, Entity preImage, Entity postImage, PluginContext pluginContext, Core core)
            {
                // Check if it is supposed to execute. Returns preemptively, if it should not.
                var entity    = entityObject as Entity;
                var entityRef = entityObject as EntityReference;

                var guid        = (entity != null) ? entity.Id : entityRef.Id;
                var logicalName = (entity != null) ? entity.LogicalName : entityRef.LogicalName;

                if (VerifyPluginTrigger(entity, logicalName, guid, preImage, postImage, pluginContext))
                {
                    var thisPluginContext = CreatePluginContext(pluginContext, guid, logicalName, preImage, postImage);

                    //Create Serviceprovider, and execute plugin
                    MockupServiceProviderAndFactory provider = new MockupServiceProviderAndFactory(core, thisPluginContext, new TracingService());
                    try
                    {
                        pluginExecute(provider);
                    }
                    catch (TargetInvocationException e)
                    {
                        ExceptionDispatchInfo.Capture(e.InnerException).Throw();
                    }

                    foreach (var parameter in thisPluginContext.SharedVariables)
                    {
                        pluginContext.SharedVariables[parameter.Key] = parameter.Value;
                    }
                }
            }
Beispiel #10
0
 internal MockupService(Core core, Guid?userId, PluginContext pluginContext) : this(core, userId, pluginContext, null)
 {
 }
Beispiel #11
0
 internal OrganizationResponse Execute(OrganizationRequest request, EntityReference userRef, PluginContext pluginContext)
 {
     return(Core.Execute(request, userRef, pluginContext));
 }
Beispiel #12
0
            public bool ShouldExecute(object entityObject, Entity preImage, Entity postImage, PluginContext pluginContext)
            {
                // Check if it is supposed to execute. Returns preemptively, if it should not.
                var entity    = entityObject as Entity;
                var entityRef = entityObject as EntityReference;

                var guid        = (entity != null) ? entity.Id : entityRef.Id;
                var logicalName = (entity != null) ? entity.LogicalName : entityRef.LogicalName;

                return(VerifyPluginTrigger(entity, logicalName, guid, preImage, postImage, pluginContext));
            }
        private bool ShouldExecute(Entity workflow, string operation, ExecutionStage stage, object entityObject, PluginContext pluginContext)
        {
            // Check if it is supposed to execute. Returns preemptively, if it should not.
            if (workflow.LogicalName != "workflow")
            {
                return(false);
            }
            var entity    = entityObject as Entity;
            var entityRef = entityObject as EntityReference;

            var guid        = entity?.Id ?? entityRef.Id;
            var logicalName = entity?.LogicalName ?? entityRef.LogicalName;


            if (workflow.GetAttributeValue <string>("primaryentity") != "" && workflow.GetAttributeValue <string>("primaryentity") != logicalName)
            {
                return(false);
            }

            checkInfiniteRecursion(pluginContext);

            var isCreate = operation.ToLower() == EventOperationStrings.Create;
            var isUpdate = operation.ToLower() == EventOperationStrings.Update;
            var isDelete = operation.ToLower() == EventOperationStrings.Delete;

            if (!isCreate && !isUpdate && !isDelete)
            {
                return(false);
            }

            if (isCreate && (!workflow.GetAttributeValue <bool?>("triggeroncreate").HasValue || !workflow.GetAttributeValue <bool?>("triggeroncreate").Value))
            {
                return(false);
            }
            if (isDelete && (!workflow.GetAttributeValue <bool?>("triggerondelete").HasValue || !workflow.GetAttributeValue <bool?>("triggerondelete").Value))
            {
                return(false);
            }
            var triggerFields = new HashSet <string>();

            if (workflow.GetAttributeValue <string>("triggeronupdateattributelist") != null)
            {
                foreach (var field in workflow.GetAttributeValue <string>("triggeronupdateattributelist").Split(','))
                {
                    triggerFields.Add(field);
                }
            }
            if (isUpdate && (
                    workflow.GetAttributeValue <string>("triggeronupdateattributelist") == null ||
                    workflow.GetAttributeValue <string>("triggeronupdateattributelist") == "" ||
                    !entity.Attributes.Any(a => workflow.GetAttributeValue <string>("triggeronupdateattributelist").Split(',').Any(f => a.Key == f))))
            {
                return(false);
            }

            var thisStage = isCreate ? workflow.GetOptionSetValue <workflow_stage>("createstage") :
                            (isDelete ? workflow.GetOptionSetValue <workflow_stage>("deletestage") : workflow.GetOptionSetValue <workflow_stage>("updatestage"));

            if (thisStage == null)
            {
                thisStage = workflow_stage.Postoperation;
            }

            if ((int)thisStage != (int)stage)
            {
                return(false);
            }

            var thisPluginContext = createPluginContext(pluginContext, workflow, thisStage, guid, logicalName);

            var parsedWorkflow = ParseWorkflow(workflow);

            if (parsedWorkflow == null)
            {
                return(false);
            }

            return(true);
        }
        private void StageIfMatch(Entity workflow, string operation, ExecutionStage stage,
                                  object entityObject, Entity preImage, Entity postImage, PluginContext pluginContext, Core core)
        {
            if (workflow.LogicalName != "workflow")
            {
                return;
            }
            var entity    = entityObject as Entity;
            var entityRef = entityObject as EntityReference;

            var guid        = entity?.Id ?? entityRef.Id;
            var logicalName = entity?.LogicalName ?? entityRef.LogicalName;

            if (workflow.GetAttributeValue <string>("primaryentity") != "" && workflow.GetAttributeValue <string>("primaryentity") != logicalName)
            {
                return;
            }

            checkInfiniteRecursion(pluginContext);

            var isCreate = operation.ToLower() == EventOperationStrings.Create;
            var isUpdate = operation.ToLower() == EventOperationStrings.Update;
            var isDelete = operation.ToLower() == EventOperationStrings.Delete;

            if (!isCreate && !isUpdate && !isDelete)
            {
                return;
            }
            if (isCreate && (!workflow.GetAttributeValue <bool?>("triggeroncreate").HasValue || !workflow.GetAttributeValue <bool?>("triggeroncreate").Value))
            {
                return;
            }
            if (isDelete && (!workflow.GetAttributeValue <bool?>("triggerondelete").HasValue || !workflow.GetAttributeValue <bool?>("triggerondelete").Value))
            {
                return;
            }
            var triggerFields = new HashSet <string>();

            if (workflow.GetAttributeValue <string>("triggeronupdateattributelist") != null)
            {
                foreach (var field in workflow.GetAttributeValue <string>("triggeronupdateattributelist").Split(','))
                {
                    triggerFields.Add(field);
                }
            }
            if (isUpdate && (
                    workflow.GetAttributeValue <string>("triggeronupdateattributelist") == null ||
                    workflow.GetAttributeValue <string>("triggeronupdateattributelist") == "" ||
                    !entity.Attributes.Any(a => workflow.GetAttributeValue <string>("triggeronupdateattributelist").Split(',').Any(f => a.Key == f))))
            {
                return;
            }

            var thisStage = isCreate ? workflow.GetOptionSetValue <workflow_stage>("createstage") :
                            (isDelete ? workflow.GetOptionSetValue <workflow_stage>("deletestage") : workflow.GetOptionSetValue <workflow_stage>("updatestage"));

            if (thisStage == null)
            {
                thisStage = workflow_stage.Postoperation;
            }

            if ((int)thisStage != (int)stage)
            {
                return;
            }

            var thisPluginContext = createPluginContext(pluginContext, workflow, thisStage, guid, logicalName);

            var parsedWorkflow = ParseWorkflow(workflow);

            if (parsedWorkflow == null)
            {
                return;
            }

            pendingAsyncWorkflows.Enqueue(new WorkflowExecutionContext(parsedWorkflow, thisPluginContext, new EntityReference(logicalName, guid)));
        }
 public WorkflowExecutionContext(WorkflowTree workflow, PluginContext pluginContext, EntityReference primaryRef)
 {
     this.workflow      = workflow;
     this.pluginContext = pluginContext;
     this.primaryRef    = primaryRef;
 }
 public void StageAsync(string operation, ExecutionStage stage,
                        object entity, Entity preImage, Entity postImage, PluginContext pluginContext, Core core)
 {
     asynchronousWorkflows.ForEach(x => StageIfMatch(x, operation, stage, entity,
                                                     preImage, postImage, pluginContext, core));
 }
Beispiel #17
0
 internal MockupServiceProviderAndFactory(Core core, PluginContext pluginContext, ITracingService tracingService)
 {
     this.core           = core;
     this.pluginContext  = pluginContext;
     this.tracingService = tracingService;
 }
Beispiel #18
0
        private void ExecuteIfMatch(Entity workflow, EventOperation operation, ExecutionStage stage,
                                    object entityObject, Entity preImage, Entity postImage, PluginContext pluginContext, Core core)
        {
            // Check if it is supposed to execute. Returns preemptively, if it should not.
            if (workflow.LogicalName != "workflow")
            {
                return;
            }
            var entity    = entityObject as Entity;
            var entityRef = entityObject as EntityReference;

            var guid        = (entity != null) ? entity.Id : entityRef.Id;
            var logicalName = (entity != null) ? entity.LogicalName : entityRef.LogicalName;


            if (workflow.GetAttributeValue <string>("primaryentity") != "" && workflow.GetAttributeValue <string>("primaryentity") != logicalName)
            {
                return;
            }

            if (pluginContext.Depth > 8)
            {
                throw new FaultException(
                          "This workflow job was canceled because the workflow that started it included an infinite loop." +
                          " Correct the workflow logic and try again.");
            }

            var isCreate = operation == EventOperation.Create;
            var isUpdate = operation == EventOperation.Update;
            var isDelete = operation == EventOperation.Delete;

            if (!isCreate && !isUpdate && !isDelete)
            {
                return;
            }

            if (isCreate && (!workflow.GetAttributeValue <bool?>("triggeroncreate").HasValue || !workflow.GetAttributeValue <bool?>("triggeroncreate").Value))
            {
                return;
            }
            if (isDelete && (!workflow.GetAttributeValue <bool?>("triggerondelete").HasValue || !workflow.GetAttributeValue <bool?>("triggerondelete").Value))
            {
                return;
            }
            var triggerFields = new HashSet <string>();

            if (workflow.GetAttributeValue <string>("triggeronupdateattributelist") != null)
            {
                foreach (var field in workflow.GetAttributeValue <string>("triggeronupdateattributelist").Split(','))
                {
                    triggerFields.Add(field);
                }
            }
            if (isUpdate && (
                    workflow.GetAttributeValue <string>("triggeronupdateattributelist") == null ||
                    workflow.GetAttributeValue <string>("triggeronupdateattributelist") == "" ||
                    !entity.Attributes.Any(a => workflow.GetAttributeValue <string>("triggeronupdateattributelist").Split(',').Any(f => a.Key == f))))
            {
                return;
            }

            var thisStage = isCreate ? workflow.GetOptionSetValue <workflow_stage>("createstage") :
                            (isDelete ? workflow.GetOptionSetValue <workflow_stage>("deletestage") : workflow.GetOptionSetValue <workflow_stage>("updatestage"));

            if (thisStage == null)
            {
                thisStage = workflow_stage.Postoperation;
            }

            if ((int)thisStage != (int)stage)
            {
                return;
            }
            // Create the plugin context
            var thisPluginContext = pluginContext.Clone();

            thisPluginContext.Mode              = ((int)workflow.GetOptionSetValue <Workflow_Mode>("mode") + 1) % 2;
            thisPluginContext.Stage             = thisStage.HasValue ? (int)thisStage : (int)workflow_stage.Postoperation;
            thisPluginContext.PrimaryEntityId   = guid;
            thisPluginContext.PrimaryEntityName = logicalName;

            var parsedWorkflow = ParseWorkflow(workflow);

            if (parsedWorkflow == null)
            {
                return;
            }
            WorkflowTree postExecution = null;

            if (thisStage == workflow_stage.Preoperation)
            {
                postExecution = ExecuteWorkflow(parsedWorkflow, preImage, thisPluginContext, core);
            }
            else
            {
                postExecution = ExecuteWorkflow(parsedWorkflow, postImage, thisPluginContext, core);
            }

            if (postExecution.Variables["Wait"] != null)
            {
                waitingWorkflows.Add(postExecution.Variables["Wait"] as WaitInfo);
            }
        }
Beispiel #19
0
            public void ExecuteIfMatch(object entityObject, Entity preImage, Entity postImage, PluginContext pluginContext, Core core)
            {
                // Check if it is supposed to execute. Returns preemptively, if it should not.
                var entity    = entityObject as Entity;
                var entityRef = entityObject as EntityReference;

                var guid        = (entity != null) ? entity.Id : entityRef.Id;
                var logicalName = (entity != null) ? entity.LogicalName : entityRef.LogicalName;

                if (entityName != "" && entityName != logicalName)
                {
                    return;
                }

                if (entity != null && metadata.GetMetadata(logicalName)?.PrimaryIdAttribute != null)
                {
                    entity[metadata.GetMetadata(logicalName).PrimaryIdAttribute] = guid;
                }

                if (pluginContext.Depth > 8)
                {
                    throw new FaultException(
                              "This workflow job was canceled because the workflow that started it included an infinite loop." +
                              " Correct the workflow logic and try again.");
                }

                if (operation == EventOperation.Update && stage == ExecutionStage.PostOperation)
                {
                    var shadowAddedAttributes = postImage.Attributes.Where(a => !preImage.Attributes.ContainsKey(a.Key) && !entity.Attributes.ContainsKey(a.Key));
                    entity = entity.CloneEntity();
                    entity.Attributes.AddRange(shadowAddedAttributes);
                }

                if (operation == EventOperation.Update && attributes.Count > 0)
                {
                    var foundAttr = false;
                    foreach (var attr in entity.Attributes)
                    {
                        if (attributes.Contains(attr.Key))
                        {
                            foundAttr = true;
                            break;
                        }
                    }
                    if (!foundAttr)
                    {
                        return;
                    }
                }

                if (entityName != "" && (operation == EventOperation.Associate || operation == EventOperation.Disassociate))
                {
                    throw new MockupException(
                              $"An {operation} plugin step was registered for a specific entity, which can only be registered on AnyEntity");
                }

                // Create the plugin context
                var thisPluginContext = pluginContext.Clone();

                thisPluginContext.Mode  = (int)this.mode;
                thisPluginContext.Stage = (int)this.stage;
                if (thisPluginContext.PrimaryEntityId == Guid.Empty)
                {
                    thisPluginContext.PrimaryEntityId = guid;
                }
                thisPluginContext.PrimaryEntityName = logicalName;

                foreach (var image in this.images)
                {
                    var type = (ImageType)image.Item3;
                    var cols = image.Item4 != null ? new ColumnSet(image.Item4.Split(',')) : new ColumnSet(true);
                    if (postImage != null && stage == ExecutionStage.PostOperation && (type == ImageType.PostImage || type == ImageType.Both))
                    {
                        thisPluginContext.PostEntityImages.Add(image.Item1, postImage.CloneEntity(metadata.GetMetadata(postImage.LogicalName), cols));
                    }
                    if (preImage != null && type == ImageType.PreImage || type == ImageType.Both)
                    {
                        thisPluginContext.PreEntityImages.Add(image.Item1, preImage.CloneEntity(metadata.GetMetadata(preImage.LogicalName), cols));
                    }
                }

                // Create service provider and execute the plugin
                MockupServiceProviderAndFactory provider = new MockupServiceProviderAndFactory(core, thisPluginContext, new TracingService());

                try {
                    pluginExecute(provider);
                } catch (TargetInvocationException e) {
                    ExceptionDispatchInfo.Capture(e.InnerException).Throw();
                }
            }
        internal WorkflowTree ExecuteWorkflow(WorkflowTree workflow, Entity primaryEntity, PluginContext pluginContext, Core core)
        {
            var provider = new MockupServiceProviderAndFactory(core, pluginContext, new TracingService());
            var service  = provider.CreateAdminOrganizationService(new MockupServiceSettings(true, true, MockupServiceSettings.Role.SDK));

            return(workflow.Execute(primaryEntity, core.TimeOffset, service, provider, provider.GetService(typeof(ITracingService)) as ITracingService));
        }
Beispiel #21
0
        private OrganizationResponse ExecuteRequest(OrganizationRequest request, EntityReference userRef, PluginContext parentPluginContext)
        {
#if !(XRM_MOCKUP_2011 || XRM_MOCKUP_2013 || XRM_MOCKUP_2015)
            if (request is AssignRequest assignRequest)
            {
                var targetEntity = dataMethods.GetEntityOrNull(assignRequest.Target);
                if (targetEntity.GetAttributeValue <EntityReference>("ownerid") != assignRequest.Assignee)
                {
                    var req = new UpdateRequest();
                    req.Target = new Entity(assignRequest.Target.LogicalName, assignRequest.Target.Id);
                    req.Target.Attributes["ownerid"] = assignRequest.Assignee;
                    Execute(req, userRef, parentPluginContext);
                }
                return(new AssignResponse());
            }

            if (request is SetStateRequest setstateRequest)
            {
                var targetEntity = dataMethods.GetEntityOrNull(setstateRequest.EntityMoniker);
                if (targetEntity.GetAttributeValue <OptionSetValue>("statecode") != setstateRequest.State ||
                    targetEntity.GetAttributeValue <OptionSetValue>("statuscode") != setstateRequest.Status)
                {
                    var req = new UpdateRequest();
                    req.Target = new Entity(setstateRequest.EntityMoniker.LogicalName, setstateRequest.EntityMoniker.Id);
                    req.Target.Attributes["statecode"]  = setstateRequest.State;
                    req.Target.Attributes["statuscode"] = setstateRequest.Status;
                    Execute(req, userRef, parentPluginContext);
                }
                return(new SetStateResponse());
            }
#endif
            if (workflowManager.GetActionDefaultNull(request.RequestName) != null)
            {
                return(ExecuteAction(request));
            }

            // Execute matching handler function
            if (RequestHandlerMap.TryGetValue(request.RequestName, out Func <OrganizationRequest, EntityReference, OrganizationResponse> executeFunc))
            {
                return(executeFunc(request, userRef));
            }

            if (settings.ExceptionFreeRequests.Contains(request.RequestName))
            {
                return(new OrganizationResponse());
            }

            throw new NotImplementedException("Execute for the given request has not been implemented yet.");
        }
Beispiel #22
0
        internal OrganizationResponse Execute(OrganizationRequest request, EntityReference userRef, PluginContext parentPluginContext)
        {
            // Setup
            dataMethods.HandleInternalPreOperations(request, userRef);

            var primaryRef = Mappings.GetPrimaryEntityReferenceFromRequest(request);

            // Create the plugin context
            var pluginContext = new PluginContext()
            {
                UserId            = userRef.Id,
                InitiatingUserId  = userRef.Id,
                MessageName       = RequestNameToMessageName(request.RequestName),
                Depth             = 1,
                OrganizationName  = dataMethods.OrganizationName,
                OrganizationId    = dataMethods.OrganizationId,
                PrimaryEntityName = primaryRef?.LogicalName,
            };

            if (primaryRef != null)
            {
                pluginContext.PrimaryEntityId = dataMethods.GetEntityId(primaryRef).GetValueOrDefault();
            }

            foreach (var prop in request.Parameters)
            {
                pluginContext.InputParameters[prop.Key] = prop.Value;
            }
            if (parentPluginContext != null)
            {
                pluginContext.ParentContext = parentPluginContext;
                pluginContext.Depth         = parentPluginContext.Depth + 1;
            }
            var buRef = GetBusinessUnit(userRef);

            Console.WriteLine($"User GUID: {userRef.Id}");
            Console.WriteLine($"BU GUID: {buRef.Id}");
            pluginContext.BusinessUnitId = buRef.Id;

            Mappings.RequestToEventOperation.TryGetValue(request.GetType(), out EventOperation? eventOp);

            var    entityInfo = GetEntityInfo(request);
            Entity preImage   = null;
            Entity postImage  = null;

            var settings = MockupExecutionContext.GetSettings(request);

            // Validation
            if (!settings.SetUnsettableFields && (request is UpdateRequest || request is CreateRequest))
            {
                var entity = request is UpdateRequest ? (request as UpdateRequest).Target : (request as CreateRequest).Target;
                dataMethods.RemoveUnsettableAttributes(request.RequestName, entity);
            }


            // Pre operation
            if (settings.TriggerProcesses && entityInfo != null)
            {
                preImage = TryRetrieve(primaryRef);
                if (preImage != null)
                {
                    primaryRef.Id = preImage.Id;
                }
                if (eventOp.HasValue)
                {
                    pluginManager.Trigger(eventOp.Value, ExecutionStage.PreOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                    workflowManager.Trigger(eventOp.Value, ExecutionStage.PreOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                }
            }
            // Core operation
            OrganizationResponse response = ExecuteRequest(request, userRef, parentPluginContext);


            // Post operation
            if (settings.TriggerProcesses && entityInfo != null)
            {
                postImage = TryRetrieve(primaryRef);
                if (eventOp.HasValue)
                {
                    pluginManager.Trigger(eventOp.Value, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                    workflowManager.Trigger(eventOp.Value, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                }
                workflowManager.ExecuteWaitingWorkflows(pluginContext, this);
            }

            return(response);
        }
Beispiel #23
0
            // Saves "execution" for Async plugins to be executed after sync plugins.
            public PluginExecutionProvider ToPluginExecution(object entityObject, Entity preImage, Entity postImage, PluginContext pluginContext, Core core)
            {
                var entity    = entityObject as Entity;
                var entityRef = entityObject as EntityReference;

                var guid        = (entity != null) ? entity.Id : entityRef.Id;
                var logicalName = (entity != null) ? entity.LogicalName : entityRef.LogicalName;

                if (VerifyPluginTrigger(entity, logicalName, guid, preImage, postImage, pluginContext))
                {
                    // Create the plugin context
                    var thisPluginContext = CreatePluginContext(pluginContext, guid, logicalName, preImage, postImage);
                    return(new PluginExecutionProvider(pluginExecute, new MockupServiceProviderAndFactory(core, thisPluginContext, new TracingService())));
                }

                return(null);
            }
Beispiel #24
0
 public XrmExtension(Core core, EntityReference userRef, PluginContext pluginContext)
 {
     _core          = core;
     _userRef       = userRef ?? throw new ArgumentNullException(nameof(userRef));
     _pluginContext = pluginContext;
 }
Beispiel #25
0
            private bool VerifyPluginTrigger(Entity entity, string logicalName, Guid guid, Entity preImage, Entity postImage, PluginContext pluginContext)
            {
                if (entityName != "" && entityName != logicalName)
                {
                    return(false);
                }

                if (entity != null && metadata.GetMetadata(logicalName)?.PrimaryIdAttribute != null)
                {
                    entity[metadata.GetMetadata(logicalName).PrimaryIdAttribute] = guid;
                }

                CheckInfiniteLoop(pluginContext);
                entity = AddPostImageAttributesToEntity(entity, preImage, postImage);
                CheckSpecialRequest();

                if (FilteredAttributesMatches(entity))
                {
                    return(true);
                }
                return(false);
            }
Beispiel #26
0
        internal OrganizationResponse Execute(OrganizationRequest request, EntityReference userRef,
                                              PluginContext parentPluginContext)
        {
            // Setup
            HandleInternalPreOperations(request, userRef);

            var primaryRef = Mappings.GetPrimaryEntityReferenceFromRequest(request);

            // Create the plugin context
            var pluginContext = new PluginContext()
            {
                UserId            = userRef.Id,
                InitiatingUserId  = userRef.Id,
                MessageName       = RequestNameToMessageName(request.RequestName),
                Depth             = 1,
                ExtensionDepth    = 1,
                OrganizationName  = this.OrganizationName,
                OrganizationId    = this.OrganizationId,
                PrimaryEntityName = primaryRef?.LogicalName,
            };

            if (primaryRef != null)
            {
                var refEntity = db.GetEntityOrNull(primaryRef);
                pluginContext.PrimaryEntityId = refEntity == null ? Guid.Empty : refEntity.Id;
            }

            foreach (var prop in request.Parameters)
            {
                pluginContext.InputParameters[prop.Key] = prop.Value;
            }

            if (parentPluginContext != null)
            {
                pluginContext.ParentContext        = parentPluginContext;
                pluginContext.Depth                = parentPluginContext.Depth + 1;
                pluginContext.ExtensionDepth       = parentPluginContext.ExtensionDepth + 1;
                parentPluginContext.ExtensionDepth = pluginContext.ExtensionDepth;
            }

            var buRef = GetBusinessUnit(userRef);

            pluginContext.BusinessUnitId = buRef.Id;

            Mappings.RequestToEventOperation.TryGetValue(request.GetType(), out string eventOp);

            var entityInfo = GetEntityInfo(request);

            var settings = MockupExecutionContext.GetSettings(request);

            // Validation
            if (!settings.SetUnsettableFields && (request is UpdateRequest || request is CreateRequest))
            {
                var entity = request is UpdateRequest
                    ? (request as UpdateRequest).Target
                    : (request as CreateRequest).Target;
                Utility.RemoveUnsettableAttributes(request.RequestName,
                                                   metadata.EntityMetadata.GetMetadata(entity.LogicalName), entity);
            }

            Entity preImage  = null;
            Entity postImage = null;

            if (settings.TriggerProcesses && entityInfo != null)
            {
                preImage = TryRetrieve(primaryRef);
                if (preImage != null)
                {
                    primaryRef.Id = preImage.Id;
                }
            }

            if (settings.TriggerProcesses && entityInfo != null)
            {
                // System Pre-validation
                pluginManager.TriggerSystem(eventOp, ExecutionStage.PreValidation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                // Pre-validation
                pluginManager.Trigger(eventOp, ExecutionStage.PreValidation, entityInfo.Item1, preImage, postImage, pluginContext, this);
            }

            //perform security checks for the request
            CheckRequestSecurity(request, userRef);

            if (settings.TriggerProcesses && entityInfo != null)
            {
                // Shared variables should be moved to parent context when transitioning from 10 to 20.
                pluginContext.ParentContext = pluginContext.Clone();
                pluginContext.SharedVariables.Clear();

                // Pre-operation
                pluginManager.Trigger(eventOp, ExecutionStage.PreOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                workflowManager.TriggerSync(eventOp, ExecutionStage.PreOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);

                // System Pre-operation
                pluginManager.TriggerSystem(eventOp, ExecutionStage.PreOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
            }

            // Core operation
            OrganizationResponse response = ExecuteRequest(request, userRef, parentPluginContext);

            // Post-operation
            if (settings.TriggerProcesses && entityInfo != null)
            {
                postImage = TryRetrieve(primaryRef);

                // In RetrieveMultipleRequests, the OutputParameters bag contains the entity collection
                if (request is RetrieveMultipleRequest)
                {
                    pluginContext.OutputParameters["BusinessEntityCollection"] =
                        (response as RetrieveMultipleResponse)?.EntityCollection;
                }

                if (!string.IsNullOrEmpty(eventOp))
                {
                    //copy the createon etc system attributes onto the target so they are available for postoperation processing
                    CopySystemAttributes(postImage, entityInfo.Item1 as Entity);

                    pluginManager.TriggerSystem(eventOp, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                    pluginManager.TriggerSync(eventOp, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                    pluginManager.StageAsync(eventOp, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);

                    workflowManager.TriggerSync(eventOp, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                    workflowManager.StageAsync(eventOp, ExecutionStage.PostOperation, entityInfo.Item1, preImage, postImage, pluginContext, this);
                }

                //When last Sync has been executed we trigger the Async jobs.
                if (parentPluginContext == null)
                {
                    pluginManager.TriggerAsyncWaitingJobs();
                    workflowManager.TriggerAsync(this);
                }

                workflowManager.ExecuteWaitingWorkflows(pluginContext, this);
            }

#if XRM_MOCKUP_365
            // Trigger Extension
            if (this.settings.MockUpExtensions.Any())
            {
                /*
                 * When moving business units, more than eight layers occur...
                 */
                if (pluginContext.ExtensionDepth > 8)
                {
                    throw new FaultException(
                              "This workflow job was canceled because the workflow that started it included an infinite loop." +
                              " Correct the workflow logic and try again.");
                }
            }

            switch (request.RequestName)
            {
            case "Create":
                var createResponse    = (CreateResponse)response;
                var entityLogicalName = ((Entity)request.Parameters["Target"]).LogicalName;

                var createdEntity =
                    GetDbRow(new EntityReference(entityLogicalName, createResponse.id))
                    .ToEntity();
                TriggerExtension(
                    new XrmExtension(this, userRef, pluginContext), request,
                    createdEntity, null, userRef);
                break;

            case "Update":
                var target        = (Entity)request.Parameters["Target"];
                var updatedEntity = GetDbRow(target.ToEntityReferenceWithKeyAttributes()).ToEntity();
                TriggerExtension(
                    new XrmExtension(this, userRef, pluginContext), request,
                    updatedEntity, preImage, userRef);
                break;

            case "Delete":
                TriggerExtension(
                    new XrmExtension(this, userRef, pluginContext), request,
                    null, preImage, userRef);
                break;
            }
#endif

            return(response);
        }
Beispiel #27
0
        private OrganizationResponse ExecuteRequest(OrganizationRequest request, EntityReference userRef, PluginContext parentPluginContext)
        {
#if !(XRM_MOCKUP_2011 || XRM_MOCKUP_2013 || XRM_MOCKUP_2015)
            if (request is AssignRequest assignRequest)
            {
                var targetEntity = db.GetEntityOrNull(assignRequest.Target);
                if (targetEntity.GetAttributeValue <EntityReference>("ownerid") != assignRequest.Assignee)
                {
                    var req = new UpdateRequest {
                        Target = new Entity(assignRequest.Target.LogicalName, assignRequest.Target.Id)
                    };
                    req.Target.Attributes["ownerid"] = assignRequest.Assignee;
                    Execute(req, userRef, parentPluginContext);
                }
                return(new AssignResponse());
            }

            if (request is SetStateRequest setstateRequest)
            {
                var targetEntity = db.GetEntityOrNull(setstateRequest.EntityMoniker);
                if (targetEntity.GetAttributeValue <OptionSetValue>("statecode") != setstateRequest.State ||
                    targetEntity.GetAttributeValue <OptionSetValue>("statuscode") != setstateRequest.Status)
                {
                    var req = new UpdateRequest {
                        Target = new Entity(setstateRequest.EntityMoniker.LogicalName, setstateRequest.EntityMoniker.Id)
                    };
                    req.Target.Attributes["statecode"]  = setstateRequest.State;
                    req.Target.Attributes["statuscode"] = setstateRequest.Status;
                    Execute(req, userRef, parentPluginContext);
                }
                return(new SetStateResponse());
            }
#endif
            if (workflowManager.GetActionDefaultNull(request.RequestName) != null)
            {
                return(ExecuteAction(request));
            }
            var handler = RequestHandlers.FirstOrDefault(x => x.HandlesRequest(request.RequestName));
            if (handler != null)
            {
                return(handler.Execute(request, userRef));
            }

            if (settings.ExceptionFreeRequests?.Contains(request.RequestName) ?? false)
            {
                return(new OrganizationResponse());
            }

            throw new NotImplementedException($"Execute for the request '{request.RequestName}' has not been implemented yet.");
        }
Beispiel #28
0
        private void ExecuteIfMatch(Entity workflow, EventOperation operation, ExecutionStage stage,
                                    object entityObject, Entity preImage, Entity postImage, PluginContext pluginContext, Core core)
        {
            // Check if it is supposed to execute. Returns preemptively, if it should not.
            if (workflow.LogicalName != "workflow")
            {
                return;
            }
            var entity    = entityObject as Entity;
            var entityRef = entityObject as EntityReference;

            var guid        = entity?.Id ?? entityRef.Id;
            var logicalName = entity?.LogicalName ?? entityRef.LogicalName;


            if (workflow.GetAttributeValue <string>("primaryentity") != "" && workflow.GetAttributeValue <string>("primaryentity") != logicalName)
            {
                return;
            }

            checkInfiniteRecursion(pluginContext);

            var isCreate = operation == EventOperation.Create;
            var isUpdate = operation == EventOperation.Update;
            var isDelete = operation == EventOperation.Delete;

            if (!isCreate && !isUpdate && !isDelete)
            {
                return;
            }

            if (isCreate && (!workflow.GetAttributeValue <bool?>("triggeroncreate").HasValue || !workflow.GetAttributeValue <bool?>("triggeroncreate").Value))
            {
                return;
            }
            if (isDelete && (!workflow.GetAttributeValue <bool?>("triggerondelete").HasValue || !workflow.GetAttributeValue <bool?>("triggerondelete").Value))
            {
                return;
            }
            var triggerFields = new HashSet <string>();

            if (workflow.GetAttributeValue <string>("triggeronupdateattributelist") != null)
            {
                foreach (var field in workflow.GetAttributeValue <string>("triggeronupdateattributelist").Split(','))
                {
                    triggerFields.Add(field);
                }
            }
            if (isUpdate && (
                    workflow.GetAttributeValue <string>("triggeronupdateattributelist") == null ||
                    workflow.GetAttributeValue <string>("triggeronupdateattributelist") == "" ||
                    !entity.Attributes.Any(a => workflow.GetAttributeValue <string>("triggeronupdateattributelist").Split(',').Any(f => a.Key == f))))
            {
                return;
            }

            var thisStage = isCreate ? workflow.GetOptionSetValue <workflow_stage>("createstage") :
                            (isDelete ? workflow.GetOptionSetValue <workflow_stage>("deletestage") : workflow.GetOptionSetValue <workflow_stage>("updatestage"));

            if (thisStage == null)
            {
                thisStage = workflow_stage.Postoperation;
            }

            if ((int)thisStage != (int)stage)
            {
                return;
            }

            var thisPluginContext = createPluginContext(pluginContext, workflow, thisStage, guid, logicalName);

            var parsedWorkflow = ParseWorkflow(workflow);

            if (parsedWorkflow == null)
            {
                return;
            }

            WorkflowTree postExecution = null;

            if (thisStage == workflow_stage.Preoperation)
            {
                postExecution = ExecuteWorkflow(parsedWorkflow, preImage.CloneEntity(), thisPluginContext, core);
            }
            else
            {
                postExecution = ExecuteWorkflow(parsedWorkflow, postImage.CloneEntity(), thisPluginContext, core);
            }

            if (postExecution.Variables["Wait"] != null)
            {
                waitingWorkflows.Add(postExecution.Variables["Wait"] as WaitInfo);
            }
        }