private void updatePreOpTest(ICDSPluginExecutionContext executionContext, TestProxy.Account target)
                {
                    Assert.AreEqual(Ids.Account, target.Id);

                    //alter the target to see if it get saved to the input parameters collection.
                    target.AccountNumber = "1";
                }
        /// <summary>
        /// Demonstration update event handler
        /// </summary>
        /// <param name="executionContext">The <see cref="ICDSPluginExecutionContext"/> execution context for
        /// the handler execution</param>
        /// <param name="target">The target entity for the update. Contains any fields that are being sent in for update.</param>
        private void workingWithEntityUpdate(ICDSPluginExecutionContext executionContext, Account target)
        {
            var setting = executionContext.Settings.GetValue <string>("ps_environmentvariablename");

            // carry out actions only if the update is affecting the name or accountnumber fields
            if (target.ContainsAny("name", "accountnumber"))
            {
                executionContext.Trace("Target contains at least one matching attribute");  // short cut to tracing service Trace method.
            }

            // TargetReference - Provides and entity reference for the entity in the InputParameters Target parameter. Return null if the entity does not exist.
            EntityReference targetRef = executionContext.TargetReference;

            // PreImage - Provides access to the first entity image in the PreEntityImages collection. Returns null if a image does not exist.
            Entity preImage = executionContext.PreImage;

            // PreMergedTarget - Provides an entity with attributes from the TargetEntity merged into the PreImage entity. If an attribute exists in
            // both the TargetEntity and the PreImage, the merged target will show the attribute from the Target.
            var mergedTarget = executionContext.PreMergedTarget.ToEntity <Account>();


            // GetRecord is a simple retrieve shortcut that accepts an EntityReference, an optional list of columns,
            // and/or a cache timeout value for caching the result, and returns an early-bound entity.
            var myRecord1 = executionContext.GetRecord <Account>(targetRef);                                           //Get record with all columns.
            var myRecord2 = executionContext.GetRecord <Account>(targetRef, new string[] { "name", "accountnumber" }); //retrieve 2 columns
            var myRecord3 = executionContext.GetRecord <Account>(targetRef, TimeSpan.FromSeconds(10));                 //retrieve and cache for 10 seconds
        }
        /// <summary>
        /// Demonstrates various features associated with the Organization Service
        /// </summary>
        /// <param name="executionContext"></param>
        private void workingWithOrgService(ICDSPluginExecutionContext executionContext)
        {
            // OrganizationService - Provides easy access to the organization service.
            // This instance of the organization service runs as user or system based on
            // the plugin RunAs execution property.
            var orgService = executionContext.OrganizationService;

            // ElevatedOrganizationService - Provides easy access to an organization service
            // instance that runs under the security context of the System User regardless
            // of plugin RunAs execution property.
            var elevatedOrgService = executionContext.ElevatedOrganizationService;


            // FluentQuery OrganizationService extension generates more readable queries than
            // standard query syntax.
            var records = orgService.Query <Account>()
                          .Select(cols => new { cols.Name, cols.AccountNumber })
                          .WhereAll(e => e
                                    .IsActive()
                                    .Attribute("name").Is <string>(ConditionOperator.BeginsWith, "C"))
                          .OrderByAsc("name", "accountnumber")
                          .Retrieve();

            var accountId = executionContext.TargetReference;

            // Load a record based on its record id
            var lateBoundRecord = orgService.GetRecord(accountId, "accountid", "name", "accountnumber");

            var earlyBoundRecord = orgService.GetRecord <Account>(accountId, cols => new { cols.Id, cols.Name, cols.AccountNumber });
        }
                private void doNothing(ICDSPluginExecutionContext executionContext)
                {
                    // Event Tracking.
                    executionContext.TrackEvent("Initiated Handler");

                    // Exception tracking handled by code.
                    try
                    {
                        throw new Exception("Handled Exception");
                    }
                    catch (Exception ex)
                    {
                        executionContext.TrackException(ex);
                    }

                    // Message Telemetry
                    executionContext.Trace("A simple message - {0}", executionContext.PrimaryEntityName);
                    executionContext.Trace(Core.eSeverityLevel.Warning, "A warning message {0}", executionContext.UserId);
                    executionContext.Trace(Core.eSeverityLevel.Critical, "A critical message");

                    // Web request dependency tracking.
                    using (var webReq = executionContext.CreateWebRequest(new Uri("http://google.com"), "myWebRequestTest"))
                    {
                        var data = webReq.Get();
                    }

                    // randomly throw an exception
                    var random = new Random();

                    if (random.Next(100) <= 10)
                    {
                        // Unhandled exception tracking logged by base plugin.
                        throw new Exception("Throw Unhandled Exception");
                    }
                }
Example #5
0
        /// <summary>
        /// Demonstrates some of the shortcuts and features around working with entities.
        /// </summary>
        /// <param name="executionContext"></param>
        private void workingWithEntities(ICDSPluginExecutionContext executionContext)
        {
            // TargetEntity - Provides access to the entity in the InputParameters Target parameter if it exists. Returns null if it does not exist.
            Entity target = executionContext.TargetEntity;

            // TargetReference - Provides and entity reference for the entity in the InputParameters Target parameter. Return null if the entity does not exist.
            EntityReference targetRef = executionContext.TargetReference;

            // PreImage - Provides access to the first entity image in the PreEntityImages collection. Returns null if a image does not exist.
            Entity preImage = executionContext.PreImage;

            // PreMergedTarget - Provides an entity with attributes from the TargetEntity merged into the PreImage entity. If an attribute exists in
            // both the TargetEntity and the PreImage, the merged target will show the attribute from the Target.
            Entity mergedTarget = executionContext.PreMergedTarget;


            // GetRecord is a simple retrieve shortcut that accepts an EntityReference, an optional list of columns,
            // and/or a cache timeout value for caching the result, and returns an earlybound entity.
            var myRecord1 = executionContext.GetRecord <Account>(targetRef);                                           //Get record with all columns.
            var myRecord2 = executionContext.GetRecord <Account>(targetRef, new string[] { "name", "accountnumber" }); //retrieve 2 columns
            var myRecord3 = executionContext.GetRecord <Account>(targetRef, TimeSpan.FromSeconds(10));                 //retrieve and cache for 10 seconds

            // ContainsAny Entity extension - Checks for existence of at least one of multiple attributes. Easier to read and understand than
            // target.Contains("name") || target.Contains("accountnumber") especially with a large set of attributes.
            if (target.ContainsAny(new string[] { "name", "accountnumber" }))
            {
                executionContext.Trace("Target contains at least one matching attribute");  // short cut to tracing service Trace method.
            }
        }
Example #6
0
        public void Invoke(ICDSPluginExecutionContext executionContext)
        {
            _ = executionContext.InputParameters["Query"] ??
                throw new ArgumentNullException("RetrieveMultiple is missing required Query input parameter.");

            if (executionContext.InputParameters["Query"] is FetchExpression)
            {
                // Convert FetchXML to query expression.
                var fetchExpression = executionContext.InputParameters["Query"] as FetchExpression;

                var conversionRequest = new FetchXmlToQueryExpressionRequest
                {
                    FetchXml = fetchExpression.Query
                };

                var conversionResponse = (FetchXmlToQueryExpressionResponse)executionContext.OrganizationService.Execute(conversionRequest);

                executionContext.InputParameters["Query"] = conversionResponse.Query;
            }

            var qryExpression = executionContext.InputParameters["Query"] as QueryExpression;


            if (Stage == ePluginStage.PostOperation)
            {
                var response = (executionContext.OutputParameters["EntityCollection"] as EntityCollection) ??
                               throw new ArgumentNullException("PostOp RetrieveMultiple Message is missing required EntityCollection output parameter.");
                PluginAction.Invoke(executionContext, qryExpression, response);
                executionContext.OutputParameters["EntityColection"] = response;
            }
            else
            {
                PluginAction.Invoke(executionContext, qryExpression, null);
            }
        }
                private void createPreOpTest(ICDSPluginExecutionContext executionContext, TestProxy.Account target, EntityReference response)
                {
                    Assert.AreEqual(Ids.Account, target.Id);
                    Assert.IsNull(response);

                    //alter the target to see if it get saved to the input parameters collection.
                    target.AccountNumber = "1";
                }
                private void createPostOpTest(ICDSPluginExecutionContext executionContext, TestProxy.Account target, EntityReference response)
                {
                    Assert.AreEqual(Ids.Account, target.Id);
                    Assert.AreEqual(default(Guid), response.Id);

                    //alter the response to see if it gets saved to the outputs collection.
                    response.Id = Guid.NewGuid();
                }
        private void PrepareForRetrieveDecryption(ICDSPluginExecutionContext executionContext, EntityReference target, ColumnSet columnSet, Entity retrievedRecord)
        {
            var factory = Container.Resolve <IEncryptedFieldServiceFactory>();

            using (var encryptionService = factory.Create(executionContext, target.LogicalName))
            {
                encryptionService.PrepareForDecryption(ref columnSet);
            }
        }
        private void LogEncryptedSearchHits(ICDSPluginExecutionContext executionContext, QueryExpression query, EntityCollection retrievedRecords)
        {
            var factory = Container.Resolve <IEncryptedFieldServiceFactory>();

            using (var encryptionService = factory.Create(executionContext, query.EntityName))
            {
                encryptionService.LogEncryptedSearchHits(retrievedRecords);
            }
        }
        private void EncryptedSearchHandler(ICDSPluginExecutionContext executionContext, QueryExpression query, EntityCollection entityCollection)
        {
            var factory = Container.Resolve <IEncryptedFieldServiceFactory>();

            using (var encryptionService = factory.Create(executionContext, query.EntityName))
            {
                encryptionService.GenerateEncryptedFieldQuery(ref query);
            }
        }
        private void EncryptOnUpdateHandler(ICDSPluginExecutionContext executionContext, Entity target)
        {
            var factory = Container.Resolve <IEncryptedFieldServiceFactory>();

            using (var encryptionService = factory.Create(executionContext, target.LogicalName))
            {
                encryptionService.EncryptFields(ref target);
            }
        }
        private void PostQueryDecryption(ICDSPluginExecutionContext executionContext, QueryExpression query, EntityCollection entityCollection)
        {
            var factory = Container.Resolve <IEncryptedFieldServiceFactory>();

            using (var encryptionService = factory.Create(executionContext, entityCollection.EntityName))
            {
                encryptionService.DecryptFields(ref entityCollection);
            }
        }
 internal EncryptedFieldService(ICDSPluginExecutionContext executionContext, string recordType, IServiceConfiguration configuration, IEncryptionServiceFactory encryptionServiceFactory, IUserRoleEvaluator roleEvaluator, IEncryptedFieldAccessLoggerFactory accessLoggerFactory)
 {
     this.ExecutionContext         = executionContext ?? throw new ArgumentNullException("executionContext");
     this.RecordType               = recordType ?? throw new ArgumentNullException("recordType");
     this.Configuration            = configuration ?? throw new ArgumentNullException("configuration");
     this.EncryptionServiceFactory = encryptionServiceFactory ?? throw new ArgumentNullException("encryptionServiceFactory");
     this.RoleEvaluator            = roleEvaluator ?? throw new ArgumentNullException("roleEvaluator");
     this.AccessLoggerFactory      = accessLoggerFactory;
 }
        private void PrepareForQueryDecryption(ICDSPluginExecutionContext executionContext, QueryExpression query, EntityCollection entityCollection)
        {
            var factory = Container.Resolve <IEncryptedFieldServiceFactory>();

            using (var encryptionService = factory.Create(executionContext, query.EntityName))
            {
                var columnSet = query.ColumnSet;
                encryptionService.PrepareForDecryption(ref columnSet);
            }
        }
        /// <summary>
        /// Demonstrates a simple GET operation using built in web request support. Will automatically
        /// generate dependency telemetry.
        /// </summary>
        /// <param name="executionContext"></param>
        private void demonstrateWebRequest(ICDSPluginExecutionContext executionContext)
        {
            Uri googleUri = new Uri("https://www.google.com");

            using (var webRequest = executionContext.CreateWebRequest(googleUri))
            {
                var result = webRequest.Get();
                executionContext.Trace("Returned {0} characters", result.Content.Length);
            }
        }
        public void Invoke(ICDSPluginExecutionContext executionContext)
        {
            var target    = (EntityReference)executionContext.InputParameters["Target"];
            var columnSet = (ColumnSet)executionContext.InputParameters["ColumnSet"];

            if (Stage == ePluginStage.PostOperation)
            {
                var response = ((Entity)(executionContext.OutputParameters["Entity"])).ToEntity <E>();
                PluginAction.Invoke(executionContext, target, columnSet, response);
                executionContext.OutputParameters["Entity"] = response;
            }
            else
            {
                PluginAction.Invoke(executionContext, target, columnSet, null);
            }
        }
        /// <summary>
        /// Prior to a new process step record creation, set the step parameter value to the template value
        /// defined on the associated step type if the value is currently blank.
        /// </summary>
        /// <param name="executionContext"></param>
        /// <param name="target"></param>
        /// <param name="createdProcessStepId"></param>
        private void addStepParameterTemplate(
            ICDSPluginExecutionContext executionContext,
            ccllc_processstep target,
            EntityReference createdProcessStepId)
        {
            if (target.ccllc_StepParameters == null && target.ccllc_ProcessStepTypeId != null)
            {
                var stepType = executionContext.OrganizationService
                               .GetRecord <ccllc_processsteptype>(target.ccllc_ProcessStepTypeId, cols => new { cols.Id, cols.ccllc_StepParameterTemplate });

                if (stepType.ccllc_StepParameterTemplate != null)
                {
                    target.ccllc_StepParameters = stepType.ccllc_StepParameterTemplate;
                }
            }
        }
 /// <summary>
 /// Prior to a new transaction type record creation, set the data record configuration parameter
 /// to a template guide value if it is blank.
 /// </summary>
 /// <param name="executionContext"></param>
 /// <param name="target"></param>
 /// <param name="createdTransactionTypeId"></param>
 private void addDataRecordParameterTemplate(
     ICDSPluginExecutionContext executionContext,
     ccllc_transactiontype target,
     EntityReference createdTransactionTypeId)
 {
     if (target.ccllc_DataRecordConfiguration is null)
     {
         target.ccllc_DataRecordConfiguration =
             "{" + Environment.NewLine +
             "\"RecordType\":\"new_entitylogicalname\"," + Environment.NewLine +
             "\"NameField\":\"new_name\"," + Environment.NewLine +
             "\"TransactionField\":\"new_transactionid\"," + Environment.NewLine +
             "\"CustomerField\":\"new_customerid\"" + Environment.NewLine +
             "}";
     }
 }
        /// <summary>
        /// After a new transaction process is created, check the startup process value on the parent transaction type record
        /// and set it to this newly created transaction process if the value is currently blank.
        /// </summary>
        /// <param name="executionContext"></param>
        /// <param name="target"></param>
        /// <param name="createdProcessId"></param>
        private void setTransactionTypeStartupProcessIfBlank(
            ICDSPluginExecutionContext executionContext,
            ccllc_transactionprocess target,
            EntityReference createdProcessId)
        {
            if (target.ccllc_TransactionTypeId != null)
            {
                var transactionType = executionContext.OrganizationService
                                      .GetRecord <ccllc_transactiontype>(target.ccllc_TransactionTypeId, cols => new { cols.Id, cols.ccllc_StartupProcessId });

                if (transactionType.ccllc_StartupProcessId is null)
                {
                    transactionType.ccllc_StartupProcessId = createdProcessId ?? throw new ArgumentNullException("createdProcessId is null");
                    executionContext.OrganizationService.Update(transactionType);
                }
            }
        }
Example #21
0
        public void Invoke(ICDSPluginExecutionContext executionContext)
        {
            E target = executionContext.TargetEntity.ToEntity <E>();



            if (Stage == ePluginStage.PostOperation)
            {
                var response = new EntityReference(this.EntityName, (Guid)executionContext.OutputParameters["id"]);
                PluginAction.Invoke(executionContext, target, response);
                executionContext.OutputParameters["id"] = response?.Id;
            }
            else
            {
                PluginAction.Invoke(executionContext, target, null);
            }
        }
Example #22
0
        /// <summary>
        /// Telemetry Sink that gathers and transmits telemetry.
        /// </summary>
        /// <param name="cdsExecutionContext"></param>
        /// <returns></returns>
        public virtual bool ConfigureTelemetrySink(ICDSPluginExecutionContext cdsExecutionContext)
        {
            if (cdsExecutionContext != null)
            {
                var key = cdsExecutionContext.Settings.GetValue <string>("Telemetry.InstrumentationKey", this.DefaultInstrumentationKey);

                if (!string.IsNullOrEmpty(key))
                {
                    TelemetrySink.ProcessChain.TelemetryProcessors.Add(new SequencePropertyProcessor());
                    TelemetrySink.ProcessChain.TelemetryProcessors.Add(new InstrumentationKeyPropertyProcessor(key));

                    return(true); //telemetry sink is configured.
                }
            }

            return(false); //telemetry sink is not configured.
        }
        internal void CanNavigateForwardHandler(ICDSPluginExecutionContext executionContext)
        {
            var req = executionContext.CreateOrganizationRequest <ccllc_BTF_CanNavigateForwardRequest>();

            EntityReference transactionId = req.Target ?? throw new NullReferenceException("Target cannot be null");
            EntityReference userId        = req.UserId ?? new EntityReference("systemuser", executionContext.InitiatingUserId);

            var systemUser = new SystemUser(userId.LogicalName, userId.Id, userId.Name);

            var platformService = Container.Resolve <IPlatformService>();
            var session         = platformService.GenerateSession(executionContext, systemUser);

            var managerFactory = Container.Resolve <ITransactionServiceFactory>();
            var manager        = managerFactory.CreateTransactionService(executionContext);

            var transaction = manager.LoadTransaction(executionContext, transactionId.ToRecordPointer());

            bool canNavigate = transaction.CanNavigateForward(session);

            executionContext.OutputParameters["IsAllowed"] = canNavigate;
        }
        public void Invoke(ICDSPluginExecutionContext executionContext)
        {
            var request = new TRequest()
            {
                Parameters = executionContext.InputParameters
            };

            if (Stage == ePluginStage.PostOperation)
            {
                var response = new TResponse()
                {
                    Results = executionContext.OutputParameters
                };

                PluginAction.Invoke(executionContext, request, response);
            }
            else
            {
                PluginAction.Invoke(executionContext, request, null);
            }
        }
        internal void NavigateBackwardHandler(ICDSPluginExecutionContext executionContext)
        {
            var req = executionContext.CreateOrganizationRequest <ccllc_BTF_NavigateBackwardRequest>();

            EntityReference transactionId = req.Target ?? throw new NullReferenceException("Target cannot be null");
            EntityReference userId        = req.UserId ?? new EntityReference("systemuser", executionContext.InitiatingUserId);

            var systemUser = new SystemUser(userId.LogicalName, userId.Id, userId.Name);

            var platformService = Container.Resolve <IPlatformService>();
            var session         = platformService.GenerateSession(executionContext, systemUser);

            var managerFactory = Container.Resolve <ITransactionServiceFactory>();
            var manager        = managerFactory.CreateTransactionService(executionContext);

            var transaction = manager.LoadTransaction(executionContext, transactionId.ToRecordPointer());

            IUIPointer uiPointer = null;
            var        step      = transaction.NavigateBackward(session);

            if (step.Type.IsUIStep)
            {
                uiPointer = step.GetUIPointer(executionContext, transaction);
            }

            if (uiPointer == null)
            {
                // At this point something is wrong so navigate the user to the transaction error form.
                uiPointer = new UIPointer
                {
                    UIDefinition = "TransactionError",
                    UIRecordId   = transaction.Id,
                    UIRecordType = "ccllc_transaction",
                    UIType       = eUIStepTypeEnum.DataForm
                };
            }

            executionContext.OutputParameters["UIPointer"] = uiPointer.Serialize();
        }
Example #26
0
        internal void GetAvailableTransactionTypeHandler(ICDSPluginExecutionContext executionContext)
        {
            var req = executionContext.CreateOrganizationRequest <ccllc_BTF_GetAvailableTransactionTypesRequest>();

            if (string.IsNullOrEmpty(req.ContextRecordType))
            {
                throw new ArgumentNullException("ContextRecordType cannot be null.");
            }
            if (string.IsNullOrEmpty(req.ContextRecordId))
            {
                throw new ArgumentNullException("ContextRecordId cannot be null.");
            }

            if (!Guid.TryParse(req.ContextRecordId, out Guid recordId))
            {
                throw new ArgumentException("ContextRecordId cannot be converted to a GUID.");
            }

            var contextRecordId = new RecordPointer <Guid>(req.ContextRecordType, recordId);

            var userId     = req.UserId ?? new EntityReference("systemuser", executionContext.InitiatingUserId);
            var systemUser = new SystemUser(userId.LogicalName, userId.Id, userId.Name);

            var platformManager = Container.Resolve <IPlatformService>();
            var session         = platformManager.GenerateSession(executionContext, systemUser);

            var contextFactory     = Container.Resolve <ITransactionContextFactory>();
            var transactionContext = contextFactory.CreateTransactionContext(executionContext, contextRecordId);


            var serviceFactory = Container.Resolve <ITransactionServiceFactory>();
            var service        = serviceFactory.CreateTransactionService(executionContext);

            var available = service.GetAvaialbleTransactionTypes(executionContext, session, transactionContext);

            executionContext.OutputParameters["TransactionTypes"] = available.Serialize();
        }
        /// <summary>
        /// After creation of a new process step, link it up to the current last step in the process so that the
        /// new step becomes the last step in the process.
        /// </summary>
        /// <param name="executionContext"></param>
        /// <param name="target"></param>
        /// <param name="createdProcessStepId"></param>
        private void addAsLastProcessStep(
            ICDSPluginExecutionContext executionContext,
            ccllc_processstep target,
            EntityReference createdProcessStepId)
        {
            if (target.ccllc_TransactionProcessId != null)
            {
                var process = executionContext.OrganizationService
                              .GetRecord <ccllc_transactionprocess>(target.ccllc_TransactionProcessId, cols => new { cols.Id, cols.ccllc_InitialProcessStepId });

                // set the process initial step to this step if it is currently null.
                if (process.ccllc_InitialProcessStepId is null)
                {
                    process.ccllc_InitialProcessStepId = createdProcessStepId;
                    executionContext.OrganizationService.Update(process);
                }

                // find last step that has a blank subsequent step id that is not the newly created step.
                var lastStep = executionContext.OrganizationService.Query <ccllc_processstep>()
                               .Select(cols => new { cols.Id, cols.ccllc_SubsequentStepId })
                               .WhereAll(s => s
                                         .IsActive()
                                         .Attribute("ccllc_transactionprocessid").IsEqualTo(process.Id)
                                         .Attribute("ccllc_subsequentstepid").IsNull()
                                         .Attribute("ccllc_processstepid").Is(Microsoft.Xrm.Sdk.Query.ConditionOperator.NotEqual, createdProcessStepId.Id))
                               .OrderByDesc("createdon")
                               .FirstOrDefault();

                // Set the subsequent step on the last step to the newly created step.
                if (lastStep != null)
                {
                    lastStep.ccllc_SubsequentStepId = createdProcessStepId;
                    executionContext.OrganizationService.Update(lastStep);
                }
            }
        }
        /// <summary>
        /// Demonstrates basic tracing and tracking methods built into the execution context.
        /// </summary>
        /// <param name="executionContext"></param>
        private void demonstrateTelemetry(ICDSPluginExecutionContext executionContext)
        {
            // Information message written to the standard tracing service and also to ApplicationInsights.
            executionContext.Trace("The primary entity type is '{0}'", executionContext.PrimaryEntityName);

            // Waring message written to the standard tracing service and also to ApplicationInsights.
            executionContext.Trace(eSeverityLevel.Warning, "A warning message for record '{0}'", executionContext.PrimaryEntityId);

            // Create an Event marker in ApplicationInsights
            executionContext.TrackEvent("Event_1");

            // Capture exception information for a handled exception in ApplicationInsights
            // Note that capturing exception telemetry for unhandled exceptions is taken care of
            // in the InstrumentedCDSPlugin abstract class.
            try
            {
                throw new Exception("Sample exception");
            }
            catch (Exception ex)
            {
                executionContext.TrackException(ex);
                // do something to handle exception
            }
        }
Example #29
0
        public void Invoke(ICDSPluginExecutionContext executionContext)
        {
            var target = executionContext.TargetReference;

            PluginAction.Invoke(executionContext, target);
        }
Example #30
0
        internal void InitiateTransactionHandler(ICDSPluginExecutionContext executionContext)
        {
            var req = (executionContext.CreateOrganizationRequest <ccllc_BTF_InitiateTransactionRequest>());

            if (string.IsNullOrEmpty(req.ContextRecordType))
            {
                throw new ArgumentNullException("ContextRecordType cannot be null.");
            }
            if (string.IsNullOrEmpty(req.ContextRecordId))
            {
                throw new ArgumentNullException("ContextRecordId cannot be null.");
            }

            if (!Guid.TryParse(req.ContextRecordId, out Guid recordId))
            {
                throw new ArgumentException("ContextRecordId cannot be converted to a GUID.");
            }

            var contextRecordId   = new RecordPointer <Guid>(req.ContextRecordType, recordId);
            var transactionTypeId = req.TransactionTypeId ?? throw new NullReferenceException("TransactionTypeId cannot be null");
            var userId            = req.UserId ?? new EntityReference("systemuser", executionContext.InitiatingUserId);

            var systemUser = new SystemUser(userId.LogicalName, userId.Id, userId.Name);

            var platformService = Container.Resolve <IPlatformService>();

            var session = platformService.GenerateSession(executionContext, systemUser);

            var contextFactory     = Container.Resolve <ITransactionContextFactory>();
            var transactionContext = contextFactory.CreateTransactionContext(executionContext, contextRecordId);

            var serviceFactory = Container.Resolve <ITransactionServiceFactory>();
            var service        = serviceFactory.CreateTransactionService(executionContext);

            var transactionType = service.GetAvaialbleTransactionTypes(executionContext, session, transactionContext).Where(r => r.Id == transactionTypeId.Id).FirstOrDefault();

            if (transactionType == null)
            {
                throw TransactionException.BuildException(TransactionException.ErrorCode.TransactionTypeNotFound);
            }

            var transaction = service.NewTransaction(executionContext, session, transactionContext, transactionType);

            IUIPointer uiPointer = null;

            if (transaction.CurrentStep.Type.IsUIStep)
            {
                uiPointer = transaction.CurrentStep.GetUIPointer(executionContext, transaction);
            }

            if (uiPointer == null)
            {
                // When current step is not a UI step, navigate the process forward which will execute process steps
                // until a UI step is found or the process is blocked by a validation issue.
                var step = transaction.NavigateForward(session);
                if (step.Type.IsUIStep)
                {
                    uiPointer = step.GetUIPointer(executionContext, transaction);
                }
            }

            if (uiPointer == null)
            {
                // At this point something is wrong so navigate the user to the transaction error form.
                uiPointer = new UIPointer
                {
                    UIDefinition = "TransactionError",
                    UIRecordId   = transaction.Id,
                    UIRecordType = "ccllc_transaction",
                    UIType       = eUIStepTypeEnum.DataForm
                };
            }

            executionContext.Trace("Adding UI Pointer to output parameters.");
            executionContext.OutputParameters["UIPointer"] = uiPointer.Serialize();
        }