public async Task OnTurnAsync(ITurnContext context, NextDelegate next, CancellationToken ct)
        {
            Activity activity = context.Activity;

            if (activity.Type is ActivityTypes.Message)
            {
                bool.TryParse(
                    Configuration[KeyRejectConnectionRequestIfNoAggregationChannel],
                    out bool rejectConnectionRequestIfNoAggregationChannel);

                // Store the conversation references (identities of the sender and the recipient [bot])
                // in the activity
                MessageRouter.StoreConversationReferences(activity);

                AbstractMessageRouterResult messageRouterResult = null;

                // Check the activity for commands
                if (await CommandHandler.HandleCommandAsync(context) == false)
                {
                    // No command detected/handled

                    // Let the message router route the activity, if the sender is connected with
                    // another user/bot
                    messageRouterResult = await MessageRouter.RouteReachMessageIfSenderIsConnectedAsync(activity);

                    if (messageRouterResult is MessageRoutingResult &&
                        (messageRouterResult as MessageRoutingResult).Type == MessageRoutingResultType.NoActionTaken)
                    {
                        // No action was taken by the message router. This means that the user
                        // is not connected (in a 1:1 conversation) with a human
                        // (e.g. customer service agent) yet.

                        // Check for cry for help (agent assistance)
                        if (!string.IsNullOrWhiteSpace(activity.Text) &&
                            activity.Text.ToLower().Contains("human"))
                        {
                            // Create a connection request on behalf of the sender
                            // Note that the returned result must be handled
                            messageRouterResult = MessageRouter.CreateConnectionRequest(
                                MessageRouter.CreateSenderConversationReference(activity),
                                rejectConnectionRequestIfNoAggregationChannel);
                        }
                        else
                        {
                            // No action taken - this middleware did not consume the activity so let it propagate
                            await next(ct).ConfigureAwait(false);
                        }
                    }
                }

                // Uncomment to see the result in a reply (may be useful for debugging)
                //if (messageRouterResult != null)
                //{
                //    await MessageRouter.ReplyToActivityAsync(activity, messageRouterResult.ToString());
                //}

                // Handle the result, if necessary
                await MessageRouterResultHandler.HandleResultAsync(messageRouterResult);
            }
        }
Пример #2
0
        /// <summary>
        /// Responds back to the sender with the simple instructions.
        /// </summary>
        /// <param name="dialogContext">The dialog context.</param>
        /// <param name="result">The result containing the message sent by the user.</param>
        private async Task OnMessageReceivedAsync(IDialogContext context, IAwaitable <IMessageActivity> result)
        {
            IMessageActivity messageActivity = await result;
            string           messageText     = messageActivity.Text;
            var activity = (Activity)context.Activity;

            if (!string.IsNullOrEmpty(messageText))
            {
                MessageRouterResultHandler messageRouterResultHandler = WebApiConfig.MessageRouterResultHandler;
                await context.PostAsync($"Veuillez patienter, vous allez être mis en contact avec un humain.");

                messageActivity.Text = "human";
                var messageRouterResult = WebApiConfig.MessageRouterManager.RequestConnection((messageActivity as Activity));
                messageRouterResult.Activity = messageActivity as Activity;
                await messageRouterResultHandler.HandleResultAsync(messageRouterResult);

                context.Done(this);
            }
        }
Пример #3
0
        /// <summary>
        /// Checks the given activity for a possible command.
        /// </summary>
        /// <param name="activity">The context containing the activity, which in turn may contain a possible command.</param>
        /// <returns>True, if a command was detected and handled. False otherwise.</returns>
        public async virtual Task <bool> HandleCommandAsync(ITurnContext context)
        {
            Activity activity = context.Activity;
            Command  command  = Command.FromMessageActivity(activity);

            if (command == null)
            {
                // Check for back channel command
                command = Command.FromChannelData(activity);
            }

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

            bool     wasHandled          = false;
            Activity replyActivity       = null;
            ConversationReference sender = MessageRouter.CreateSenderConversationReference(activity);

            switch (command.BaseCommand)
            {
            case Commands.ShowOptions:
                // Present all command options in a card
                replyActivity = CommandCardFactory.AddCardToActivity(
                    activity.CreateReply(), CommandCardFactory.CreateCommandOptionsCard(activity.Recipient?.Name));
                wasHandled = true;
                break;

            case Commands.Watch:
                // Add the sender's channel/conversation into the list of aggregation channels
                bool isPermittedAggregationChannel = false;

                if (_permittedAggregationChannels != null && _permittedAggregationChannels.Count > 0)
                {
                    foreach (string permittedAggregationChannel in _permittedAggregationChannels)
                    {
                        if (!string.IsNullOrWhiteSpace(activity.ChannelId) &&
                            activity.ChannelId.ToLower().Equals(permittedAggregationChannel.ToLower()))
                        {
                            isPermittedAggregationChannel = true;
                            break;
                        }
                    }
                }
                else
                {
                    isPermittedAggregationChannel = true;
                }

                if (isPermittedAggregationChannel)
                {
                    ConversationReference aggregationChannelToAdd = new ConversationReference(
                        null, null, null,
                        activity.Conversation, activity.ChannelId, activity.ServiceUrl);

                    ModifyRoutingDataResult modifyRoutingDataResult =
                        _messageRouter.RoutingDataManager.AddAggregationChannel(aggregationChannelToAdd);

                    if (modifyRoutingDataResult.Type == ModifyRoutingDataResultType.Added)
                    {
                        replyActivity = activity.CreateReply(Strings.AggregationChannelSet);
                    }
                    else if (modifyRoutingDataResult.Type == ModifyRoutingDataResultType.AlreadyExists)
                    {
                        replyActivity = activity.CreateReply(Strings.AggregationChannelAlreadySet);
                    }
                    else if (modifyRoutingDataResult.Type == ModifyRoutingDataResultType.Error)
                    {
                        replyActivity = activity.CreateReply(
                            string.Format(Strings.FailedToSetAggregationChannel, modifyRoutingDataResult.ErrorMessage));
                    }
                }
                else
                {
                    replyActivity = activity.CreateReply(
                        string.Format(Strings.NotPermittedAggregationChannel, activity.ChannelId));
                }

                wasHandled = true;
                break;

            case Commands.Unwatch:
                // Remove the sender's channel/conversation from the list of aggregation channels
                if (_messageRouter.RoutingDataManager.IsAssociatedWithAggregation(sender))
                {
                    ConversationReference aggregationChannelToRemove = new ConversationReference(
                        null, null, null,
                        activity.Conversation, activity.ChannelId, activity.ServiceUrl);

                    if (_messageRouter.RoutingDataManager.RemoveAggregationChannel(aggregationChannelToRemove))
                    {
                        replyActivity = activity.CreateReply(Strings.AggregationChannelRemoved);
                    }
                    else
                    {
                        replyActivity = activity.CreateReply(Strings.FailedToRemoveAggregationChannel);
                    }

                    wasHandled = true;
                }

                break;

            case Commands.GetRequests:
                IList <ConnectionRequest> connectionRequests =
                    _messageRouter.RoutingDataManager.GetConnectionRequests();

                replyActivity = activity.CreateReply();

                if (connectionRequests.Count == 0)
                {
                    replyActivity.Text = Strings.NoPendingRequests;
                }
                else
                {
                    replyActivity.Attachments = CommandCardFactory.CreateMultipleConnectionRequestCards(
                        connectionRequests, activity.Recipient?.Name);
                }

                replyActivity.ChannelData = JsonConvert.SerializeObject(connectionRequests);
                wasHandled = true;
                break;

            case Commands.AcceptRequest:
            case Commands.RejectRequest:
                // Accept/reject connection request
                bool doAccept = (command.BaseCommand == Commands.AcceptRequest);

                if (_messageRouter.RoutingDataManager.IsAssociatedWithAggregation(sender))
                {
                    // The sender is associated with the aggregation and has the right to accept/reject
                    if (command.Parameters.Count == 0)
                    {
                        replyActivity = activity.CreateReply();

                        connectionRequests =
                            _messageRouter.RoutingDataManager.GetConnectionRequests();

                        if (connectionRequests.Count == 0)
                        {
                            replyActivity.Text = Strings.NoPendingRequests;
                        }
                        else
                        {
                            replyActivity = CommandCardFactory.AddCardToActivity(
                                replyActivity, CommandCardFactory.CreateMultiConnectionRequestCard(
                                    connectionRequests, doAccept, activity.Recipient?.Name));
                        }
                    }
                    else if (!doAccept &&
                             command.Parameters[0].Equals(Command.CommandParameterAll))
                    {
                        // Reject all pending connection requests
                        if (!await _connectionRequestHandler.RejectAllPendingRequestsAsync(
                                _messageRouter, _messageRouterResultHandler))
                        {
                            replyActivity      = activity.CreateReply();
                            replyActivity.Text = Strings.FailedToRejectPendingRequests;
                        }
                    }
                    else if (command.Parameters.Count > 1)
                    {
                        // Try to accept/reject the specified connection request
                        ChannelAccount requestorChannelAccount =
                            new ChannelAccount(command.Parameters[0]);
                        ConversationAccount requestorConversationAccount =
                            new ConversationAccount(null, null, command.Parameters[1]);

                        AbstractMessageRouterResult messageRouterResult =
                            await _connectionRequestHandler.AcceptOrRejectRequestAsync(
                                _messageRouter, _messageRouterResultHandler, sender, doAccept,
                                requestorChannelAccount, requestorConversationAccount);

                        await _messageRouterResultHandler.HandleResultAsync(messageRouterResult);
                    }
                    else
                    {
                        replyActivity = activity.CreateReply(Strings.InvalidOrMissingCommandParameter);
                    }
                }
#if DEBUG
                // We shouldn't respond to command attempts by regular users, but I guess
                // it's okay when debugging
                else
                {
                    replyActivity = activity.CreateReply(Strings.ConnectionRequestResponseNotAllowed);
                }
#endif

                wasHandled = true;
                break;

            case Commands.Disconnect:
                // End the 1:1 conversation(s)
                IList <ConnectionResult> disconnectResults = _messageRouter.Disconnect(sender);

                if (disconnectResults != null && disconnectResults.Count > 0)
                {
                    foreach (ConnectionResult disconnectResult in disconnectResults)
                    {
                        await _messageRouterResultHandler.HandleResultAsync(disconnectResult);
                    }

                    wasHandled = true;
                }

                break;

            default:
                replyActivity = activity.CreateReply(string.Format(Strings.CommandNotRecognized, command.BaseCommand));
                break;
            }

            if (replyActivity != null)
            {
                await context.SendActivity(replyActivity);
            }

            return(wasHandled);
        }
Пример #4
0
        /// <summary>
        /// Checks the given activity for a possible command.
        ///
        /// All messages that start with a specific command keyword or contain a mention of the bot
        /// ("@<bot name>") are checked for possible commands.
        /// </summary>
        /// <param name="activity">An Activity instance containing a possible command.</param>
        /// <returns>True, if a command was detected and handled. False otherwise.</returns>
        public async virtual Task <bool> HandleCommandAsync(Activity activity)
        {
            bool     wasHandled    = false;
            Activity replyActivity = null;
            Command  command       = ExtractCommand(activity);

            if (command != null)
            {
                Party senderParty = MessagingUtils.CreateSenderParty(activity);

                switch (command.BaseCommand.ToLower())
                {
                case string baseCommand when(baseCommand.Equals(Commands.CommandListOptions)):
                    // Present all command options in a card
                    replyActivity = CommandCardFactory.AddCardToActivity(
                        activity.CreateReply(), CommandCardFactory.CreateCommandOptionsCard(activity.Recipient?.Name));

                    wasHandled = true;
                    break;

                case string baseCommand when(baseCommand.Equals(Commands.CommandAddAggregationChannel)):
                    // Establish the sender's channel/conversation as an aggreated one if not already exists
                    Party aggregationPartyToAdd =
                        new Party(activity.ServiceUrl, activity.ChannelId, null, activity.Conversation);

                    if (_messageRouterManager.RoutingDataManager.AddAggregationParty(aggregationPartyToAdd))
                    {
                        replyActivity = activity.CreateReply(ConversationText.AggregationChannelSet);
                    }
                    else
                    {
                        replyActivity = activity.CreateReply(ConversationText.AggregationChannelAlreadySet);
                    }

                    wasHandled = true;
                    break;

                case string baseCommand when(baseCommand.Equals(Commands.CommandRemoveAggregationChannel)):
                    // Remove the sender's channel/conversation from the list of aggregation channels
                    if (_messageRouterManager.RoutingDataManager.IsAssociatedWithAggregation(senderParty))
                    {
                        Party aggregationPartyToRemove =
                            new Party(activity.ServiceUrl, activity.ChannelId, null, activity.Conversation);

                        if (_messageRouterManager.RoutingDataManager.RemoveAggregationParty(aggregationPartyToRemove))
                        {
                            replyActivity = activity.CreateReply(ConversationText.AggregationChannelRemoved);
                        }
                        else
                        {
                            replyActivity = activity.CreateReply(ConversationText.FailedToRemoveAggregationChannel);
                        }

                        wasHandled = true;
                    }

                    break;

                case string baseCommand when(baseCommand.Equals(Commands.CommandAcceptRequest) || baseCommand.Equals(Commands.CommandRejectRequest)):
                    // Accept/reject conversation request
                    bool doAccept = baseCommand.Equals(Commands.CommandAcceptRequest);

                    if (_messageRouterManager.RoutingDataManager.IsAssociatedWithAggregation(senderParty))
                    {
                        // The party is associated with the aggregation and has the right to accept/reject
                        if (command.Parameters.Count == 0)
                        {
                            replyActivity = activity.CreateReply();

                            IList <Party> pendingRequests =
                                _messageRouterManager.RoutingDataManager.GetPendingRequests();

                            if (pendingRequests.Count == 0)
                            {
                                replyActivity.Text = ConversationText.NoPendingRequests;
                            }
                            else
                            {
                                replyActivity = CommandCardFactory.AddCardToActivity(
                                    replyActivity, CommandCardFactory.CreateAcceptOrRejectCardForMultipleRequests(
                                        pendingRequests, doAccept, activity.Recipient?.Name));
                            }
                        }
                        else if (!doAccept &&
                                 command.Parameters[0].Equals(Commands.CommandParameterAll))
                        {
                            if (!await new MessageRoutingUtils().RejectAllPendingRequestsAsync(
                                    _messageRouterManager, _messageRouterResultHandler))
                            {
                                replyActivity      = activity.CreateReply();
                                replyActivity.Text = ConversationText.FailedToRejectPendingRequests;
                            }
                        }
                        else
                        {
                            string errorMessage = await new MessageRoutingUtils().AcceptOrRejectRequestAsync(
                                _messageRouterManager, _messageRouterResultHandler, senderParty, doAccept, command.Parameters[0]);

                            if (!string.IsNullOrEmpty(errorMessage))
                            {
                                replyActivity      = activity.CreateReply();
                                replyActivity.Text = errorMessage;
                            }
                        }
                    }
#if DEBUG
                    // We shouldn't respond to command attempts by regular users, but I guess
                    // it's okay when debugging
                    else
                    {
                        replyActivity = activity.CreateReply(ConversationText.ConnectionRequestResponseNotAllowed);
                    }
#endif

                    wasHandled = true;
                    break;

                case string baseCommand when(baseCommand.Equals(Commands.CommandDisconnect)):
                    // End the 1:1 conversation
                    IList <MessageRouterResult> messageRouterResults = _messageRouterManager.Disconnect(senderParty);

                    foreach (MessageRouterResult messageRouterResult in messageRouterResults)
                    {
                        await _messageRouterResultHandler.HandleResultAsync(messageRouterResult);
                    }

                    wasHandled = true;
                    break;


                    #region Implementation of debugging commands
#if DEBUG
                case string baseCommand when(baseCommand.Equals(Commands.CommandDeleteAllRoutingData)):
                    // DELETE ALL ROUTING DATA
                    replyActivity = activity.CreateReply(ConversationText.DeletingAllData);

                    _messageRouterManager.RoutingDataManager.DeleteAll();
                    wasHandled = true;
                    break;

                case string baseCommand when(baseCommand.Equals(Commands.CommandList)):
                    bool listAll = command.Parameters.Contains(Commands.CommandParameterAll);

                    replyActivity = activity.CreateReply();
                    string replyMessageText = string.Empty;

                    if (listAll || command.Parameters.Contains(Commands.CommandParameterParties))
                    {
                        // List user and bot parties
                        IRoutingDataManager routingDataManager = _messageRouterManager.RoutingDataManager;
                        string partiesAsString = PartyListToString(routingDataManager.GetUserParties());

                        replyMessageText += string.IsNullOrEmpty(partiesAsString)
                                ? $"{ConversationText.NoUsersStored}{StringAndCharConstants.LineBreak}"
                                : $"{ConversationText.Users}:{StringAndCharConstants.LineBreak}{partiesAsString}{StringAndCharConstants.LineBreak}";

                        partiesAsString = PartyListToString(routingDataManager.GetBotParties());

                        replyMessageText += string.IsNullOrEmpty(partiesAsString)
                                ? $"{ConversationText.NoBotsStored}{StringAndCharConstants.LineBreak}"
                                : $"{ConversationText.Bots}:{StringAndCharConstants.LineBreak}{partiesAsString}{StringAndCharConstants.LineBreak}";

                        wasHandled = true;
                    }

                    if (listAll || command.Parameters.Contains(Commands.CommandParameterRequests))
                    {
                        // List all pending requests
                        IList <Attachment> attachments =
                            CommandCardFactory.CreateMultipleRequestCards(
                                _messageRouterManager.RoutingDataManager.GetPendingRequests(), activity.Recipient?.Name);

                        if (attachments.Count > 0)
                        {
                            replyMessageText += string.Format(ConversationText.PendingRequestsFoundWithCount, attachments.Count);
                            replyMessageText += StringAndCharConstants.LineBreak;
                            replyActivity.AttachmentLayout = AttachmentLayoutTypes.Carousel;
                            replyActivity.Attachments      = attachments;
                        }
                        else
                        {
                            replyMessageText += $"{ConversationText.NoPendingRequests}{StringAndCharConstants.LineBreak}";
                        }

                        wasHandled = true;
                    }

                    if (listAll || command.Parameters.Contains(Commands.CommandParameterConnections))
                    {
                        // List all connections (conversations)
                        string connectionsAsString = _messageRouterManager.RoutingDataManager.ConnectionsToString();

                        replyMessageText += string.IsNullOrEmpty(connectionsAsString)
                                ? $"{ConversationText.NoConversations}{StringAndCharConstants.LineBreak}"
                                : $"{connectionsAsString}{StringAndCharConstants.LineBreak}";

                        wasHandled = true;
                    }

                    if (listAll || command.Parameters.Contains(Commands.CommandParameterResults))
                    {
                        // List all logged message router results
                        string resultsAsString = _messageRouterManager.RoutingDataManager.GetLastMessageRouterResults();

                        replyMessageText += string.IsNullOrEmpty(resultsAsString)
                                ? $"{ConversationText.NoResults}{StringAndCharConstants.LineBreak}"
                                : $"{resultsAsString}{StringAndCharConstants.LineBreak}";

                        wasHandled = true;
                    }

                    if (!wasHandled)
                    {
                        replyMessageText = ConversationText.InvalidOrMissingCommandParameter;
                    }

                    replyActivity.Text = replyMessageText;
                    break;
#endif
                    #endregion

                default:
                    replyActivity = activity.CreateReply(string.Format(ConversationText.CommandNotRecognized, command.BaseCommand));
                    break;
                }

                if (replyActivity != null)
                {
                    ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
                    await connector.Conversations.ReplyToActivityAsync(replyActivity);
                }
            }

            return(wasHandled);
        }
Пример #5
0
        /// <summary>
        /// Handles the received message.
        /// </summary>
        public async Task <HttpResponseMessage> Post([FromBody] Activity activity)
        {
            if (activity.Locale != null)
            {
                ConversationText.Culture = new CultureInfo(activity.Locale);
            }

            if (activity.Type == ActivityTypes.Message)
            {
                MessageRouterManager       messageRouterManager       = WebApiConfig.MessageRouterManager;
                MessageRouterResultHandler messageRouterResultHandler = WebApiConfig.MessageRouterResultHandler;
                bool rejectConnectionRequestIfNoAggregationChannel    =
                    WebApiConfig.Settings.RejectConnectionRequestIfNoAggregationChannel;

                messageRouterManager.MakeSurePartiesAreTracked(activity);

                // First check for commands (both from back channel and the ones directly typed)
                MessageRouterResult messageRouterResult =
                    WebApiConfig.BackChannelMessageHandler.HandleBackChannelMessage(activity);

                if (messageRouterResult.Type != MessageRouterResultType.Connected &&
                    await WebApiConfig.CommandMessageHandler.HandleCommandAsync(activity) == false)
                {
                    // No valid back channel (command) message or typed command detected

                    // Let the message router manager instance handle the activity
                    messageRouterResult = await messageRouterManager.HandleActivityAsync(
                        activity, false, rejectConnectionRequestIfNoAggregationChannel);

                    if (messageRouterResult.Type == MessageRouterResultType.NoActionTaken)
                    {
                        // No action was taken by the message router manager. This means that the
                        // user is not connected (in a 1:1 conversation) with a human
                        // (e.g. customer service agent) yet.
                        //
                        // You can, for example, check if the user (customer) needs human
                        // assistance here or forward the activity to a dialog. You could also do
                        // the check in the dialog too...
                        //
                        // Here's an example:
                        if (!string.IsNullOrEmpty(activity.Text) &&
                            activity.Text.ToLower().Contains(Commands.CommandRequestConnection))
                        {
                            messageRouterResult = messageRouterManager.RequestConnection(
                                activity, rejectConnectionRequestIfNoAggregationChannel);
                        }
                        else
                        {
                            await Conversation.SendAsync(activity, () => new RootDialog());
                        }
                    }
                }

                // Uncomment to see the result in a reply (may be useful for debugging)
                //await MessagingUtils.ReplyToActivityAsync(activity, messageRouterResult.ToString());

                // Handle the result, if required
                await messageRouterResultHandler.HandleResultAsync(messageRouterResult);
            }
            else
            {
                HandleSystemMessage(activity);
            }

            var response = Request.CreateResponse(HttpStatusCode.OK);

            return(response);
        }
Пример #6
0
        public async Task OnTurnAsync(ITurnContext context, NextDelegate next, CancellationToken ct)
        {
            Activity activity = context.Activity;
            var      conversationStateAccessors = _conversationState.CreateProperty <Conversacion>(nameof(Conversacion));
            var      conversationData           = await conversationStateAccessors.GetAsync(context, () => new Conversacion());

            var userStateAccessors = _userState.CreateProperty <Conversacion>(nameof(Conversacion));
            var conversacion       = await userStateAccessors.GetAsync(context, () => new Conversacion());

            if (activity.Type is ActivityTypes.Message)
            {
                bool.TryParse(
                    Configuration[KeyRejectConnectionRequestIfNoAggregationChannel],
                    out bool rejectConnectionRequestIfNoAggregationChannel);

                // Store the conversation references (identities of the sender and the recipient [bot])
                // in the activity
                MessageRouter.StoreConversationReferences(activity);

                AbstractMessageRouterResult messageRouterResult = null;

                // Check the activity for commands
                if (await CommandHandler.HandleCommandAsync(context) == false)
                {
                    // No command detected/handled

                    // Let the message router route the activity, if the sender is connected with
                    // another user/bot
                    messageRouterResult = await MessageRouter.RouteMessageIfSenderIsConnectedAsync(activity);

                    if (messageRouterResult is MessageRoutingResult &&
                        (messageRouterResult as MessageRoutingResult).Type == MessageRoutingResultType.NoActionTaken)
                    {
                        // No action was taken by the message router. This means that the user
                        // is not connected (in a 1:1 conversation) with a human
                        // (e.g. customer service agent) yet.

                        // Check for cry for help (agent assistance)
                        if (!string.IsNullOrWhiteSpace(activity.Text) &&
                            activity.Text.ToLower().Contains("agente"))
                        {
                            conversacion.Eleccion = activity.Text.ToLower();
                            await _conversationState.SaveChangesAsync(context, false, ct);

                            await _userState.SaveChangesAsync(context, false, ct);

                            // Create a connection request on behalf of the sender
                            // Note that the returned result must be handled
                            await context.SendActivityAsync($"{context.Activity.From.Name}, te voy a comunicar con un agente");

                            await context.SendActivityAsync("Por favor esperame unos segundos a que uno de nuestros agentes esté disponible para atenderte...");

                            messageRouterResult = MessageRouter.CreateConnectionRequest(
                                MessageRouter.CreateSenderConversationReference(activity),
                                rejectConnectionRequestIfNoAggregationChannel);
                        }
                        else
                        {
                            // No action taken - this middleware did not consume the activity so let it propagate
                            await next(ct).ConfigureAwait(false);
                        }
                    }
                }

                // Uncomment to see the result in a reply (may be useful for debugging)
                //if (messageRouterResult != null)
                //{
                //    await MessageRouter.ReplyToActivityAsync(activity, messageRouterResult.ToString());
                //}

                // Handle the result, if necessary
                await MessageRouterResultHandler.HandleResultAsync(messageRouterResult);
            }
            else
            {
                // No action taken - this middleware did not consume the activity so let it propagate
                await next(ct).ConfigureAwait(false);
            }
        }