예제 #1
0
        /// <summary>
        /// Process method checks for presence of a session id and sequence
        /// number. If they do not exist then they are initialized in evidence.
        /// If they do exist in evidence then the sequence number is incremented
        /// and added back to the evidence.
        /// </summary>
        /// <param name="data">
        /// The <see cref="IFlowData"/> instance to process.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if the supplied data instance is null
        /// </exception>
        protected override void ProcessInternal(IFlowData data)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            var evidence = data.GetEvidence().AsDictionary();

            // If the evidence does not contain a session id then create a new one.
            if (evidence.ContainsKey(Constants.EVIDENCE_SESSIONID) == false)
            {
                data.AddEvidence(Constants.EVIDENCE_SESSIONID, GetNewSessionId());
            }

            // If the evidence does not have a sequence then add one. Otherwise
            // increment it.
            if (evidence.ContainsKey(Constants.EVIDENCE_SEQUENCE) == false)
            {
                data.AddEvidence(Constants.EVIDENCE_SEQUENCE, 1);
            }
            else if (evidence.TryGetValue(Constants.EVIDENCE_SEQUENCE, out object sequence))
            {
                if (sequence is int result || (sequence is string seq && int.TryParse(seq, out result)))
                {
                    data.AddEvidence(Constants.EVIDENCE_SEQUENCE, result + 1);
                }
                else
                {
                    data.AddError(new Exception(Messages.MessageFailSequenceNumberParse), this);
                    Logger.LogError(Messages.MessageFailSequenceNumberIncrement);
                }
            }
        /// <summary>
        /// Called by the Process method on the
        /// <see cref="FlowElementBase{T, TMeta}"/> base class.
        /// Executes all child elements in parallel.
        /// </summary>
        /// <param name="data">
        /// The data to use when executing the flow elements.
        /// </param>
        protected override void ProcessInternal(IFlowData data)
        {
            List <Task> allTasks = new List <Task>();

            foreach (var element in _flowElements)
            {
                allTasks.Add(
                    // Run each element on a new thread.
                    Task.Run(() =>
                {
                    element.Process(data);
                }).ContinueWith(t =>
                {
                    // If any exceptions occurred then add them to the
                    // flow data.
                    if (t.Exception != null)
                    {
                        foreach (var innerException in t.Exception.InnerExceptions)
                        {
                            data.AddError(innerException, element);
                        }
                    }
                }, TaskScheduler.Default));
            }

            // Wait until all tasks have completed.
            Task.WhenAll(allTasks).Wait();
        }
예제 #3
0
        /// <summary>
        /// Process the given <see cref="IFlowData"/> using the
        /// <see cref="IFlowElement"/>s in the pipeline.
        /// </summary>
        /// <param name="data">
        /// The <see cref="IFlowData"/> that contains the evidence and will
        /// allow the user to access the results.
        /// </param>
        public void Process(IFlowData data)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            _logger.LogDebug($"Pipeline '{GetHashCode()}' started processing.");

            foreach (var element in _flowElements)
            {
                try
                {
                    element.Process(data);
#pragma warning disable CS0618 // Type or member is obsolete
                    // This usage will be replaced once the Cancellation Token
                    // mechanism is available.
                    if (data.Stop)
                    {
                        break;
                    }
#pragma warning restore CS0618 // Type or member is obsolete
                }
#pragma warning disable CA1031 // Do not catch general exception types
                // We want to catch any exception here so that the
                // Pipeline can manage it.
                catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    // If an error occurs then store it in the
                    // FlowData object.
                    data.AddError(ex, element);
                }
            }

            // If any errors have occurred and exceptions are not
            // suppressed, then throw an aggregate exception.
            if (data.Errors != null &&
                data.Errors.Count > 0 &&
                _suppressProcessExceptions == false)
            {
                throw new AggregateException(data.Errors
                                             .Where(e => e.ShouldThrow == true)
                                             .Select(e => e.ExceptionData));
            }

            _logger.LogDebug($"Pipeline '{GetHashCode()}' finished processing.");
        }
        /// <summary>
        /// Create and populate a JSON string from the specified data.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="config">The configuration to use</param>
        /// <returns>
        /// A string containing the data in JSON format.
        /// </returns>
        protected virtual string BuildJson(IFlowData data, PipelineConfig config)
        {
            int sequenceNumber = GetSequenceNumber(data);

            // Get property values from all the elements and add the ones that
            // are accessible to a dictionary.
            Dictionary <String, object> allProperties = GetAllProperties(data, config);

            // Only populate the JavaScript properties if the sequence
            // has not reached max iterations.
            if (sequenceNumber < Constants.MAX_JAVASCRIPT_ITERATIONS)
            {
                AddJavaScriptProperties(data, allProperties);
            }

            AddErrors(data, allProperties);

            try
            {
                return(BuildJson(allProperties));
            }
            catch (JsonWriterException jsonEx)
            {
                StringBuilder msg = new StringBuilder();
                msg.AppendLine("Error converting data to json string");
                msg.AppendLine("[");
                foreach (var entry in allProperties)
                {
                    msg.AppendLine($"  '{entry.Key}' = {GetObjectAsString(entry.Value, 2)}");
                }
                msg.AppendLine("]");
                var exception = new PipelineDataException(msg.ToString(), jsonEx);
                data.AddError(exception, this);
            }
            return("{ \"error\": \"see flow data errors for more detail\" }");
        }