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; }
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); } } }
/// <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); } }
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); }
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))); }
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); }
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; } } }
internal MockupService(Core core, Guid?userId, PluginContext pluginContext) : this(core, userId, pluginContext, null) { }
internal OrganizationResponse Execute(OrganizationRequest request, EntityReference userRef, PluginContext pluginContext) { return(Core.Execute(request, userRef, pluginContext)); }
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)); }
internal MockupServiceProviderAndFactory(Core core, PluginContext pluginContext, ITracingService tracingService) { this.core = core; this.pluginContext = pluginContext; this.tracingService = tracingService; }
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); } }
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)); }
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."); }
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); }
// 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); }
public XrmExtension(Core core, EntityReference userRef, PluginContext pluginContext) { _core = core; _userRef = userRef ?? throw new ArgumentNullException(nameof(userRef)); _pluginContext = pluginContext; }
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); }
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); }
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."); }
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); } }