Exemple #1
0
        /// <summary>
        /// Sends a set of activities to the sender of the incoming activity.
        /// </summary>
        /// <param name="activities">The activities to send.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <returns>A task that represents the work queued to execute.</returns>
        /// <remarks>If the activities are successfully sent, the task result contains
        /// an array of <see cref="ResourceResponse"/> objects containing the IDs that
        /// the receiving channel assigned to the activities.</remarks>
        public Task <ResourceResponse[]> SendActivitiesAsync(IActivity[] activities, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (activities == null)
            {
                throw new ArgumentNullException(nameof(activities));
            }

            if (activities.Length == 0)
            {
                throw new ArgumentException("Expecting one or more activities, but the array was empty.", nameof(activities));
            }

            var conversationReference = this.Activity.GetConversationReference();

            var bufferedActivities = new List <Activity>(activities.Length);

            for (var index = 0; index < activities.Length; index++)
            {
                // Buffer the incoming activities into a List<T> since we allow the set to be manipulated by the callbacks
                // Bind the relevant Conversation Reference properties, such as URLs and
                // ChannelId's, to the activity we're about to send
                bufferedActivities.Add(activities[index].ApplyConversationReference(conversationReference));
            }

            // If there are no callbacks registered, bypass the overhead of invoking them and send directly to the adapter
            if (_onSendActivities.Count == 0)
            {
                return(SendActivitiesThroughAdapter());
            }

            // Send through the full callback pipeline
            return(SendActivitiesThroughCallbackPipeline());

            Task <ResourceResponse[]> SendActivitiesThroughCallbackPipeline(int nextCallbackIndex = 0)
            {
                // If we've executed the last callback, we now send straight to the adapter
                if (nextCallbackIndex == _onSendActivities.Count)
                {
                    return(SendActivitiesThroughAdapter());
                }

                return(_onSendActivities[nextCallbackIndex].Invoke(this, bufferedActivities, () => SendActivitiesThroughCallbackPipeline(nextCallbackIndex + 1)));
            }

            async Task <ResourceResponse[]> SendActivitiesThroughAdapter()
            {
                if (Activity.DeliveryMode == DeliveryModes.ExpectReplies)
                {
                    var responses            = new ResourceResponse[bufferedActivities.Count];
                    var sentNonTraceActivity = false;

                    for (var index = 0; index < responses.Length; index++)
                    {
                        var activity = bufferedActivities[index];
                        BufferedReplyActivities.Add(activity);

                        // Ensure the TurnState has the InvokeResponseKey, since this activity
                        // is not being sent through the adapter, where it would be added to TurnState.
                        if (activity.Type == ActivityTypesEx.InvokeResponse)
                        {
                            TurnState.Add(BotFrameworkAdapter.InvokeResponseKey, activity);
                        }

                        responses[index] = new ResourceResponse();

                        sentNonTraceActivity |= activity.Type != ActivityTypes.Trace;
                    }

                    if (sentNonTraceActivity)
                    {
                        Responded = true;
                    }

                    return(responses);
                }
                else
                {
                    // Send from the list which may have been manipulated via the event handlers.
                    // Note that 'responses' was captured from the root of the call, and will be
                    // returned to the original caller.
                    var responses = await Adapter.SendActivitiesAsync(this, bufferedActivities.ToArray(), cancellationToken).ConfigureAwait(false);

                    var sentNonTraceActivity = false;

                    for (var index = 0; index < responses.Length; index++)
                    {
                        var activity = bufferedActivities[index];

                        activity.Id = responses[index].Id;

                        sentNonTraceActivity |= activity.Type != ActivityTypes.Trace;
                    }

                    if (sentNonTraceActivity)
                    {
                        Responded = true;
                    }

                    return(responses);
                }
            }
        }