protected virtual async Task OnTeamsMembersAddedDispatchAsync(IList <ChannelAccount> membersAdded, TeamInfo teamInfo, ITurnContext <IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
        {
            IDictionary <string, TeamsChannelAccount> teamMembers = null;

            var teamsMembersAdded = new List <TeamsChannelAccount>();

            foreach (var memberAdded in membersAdded)
            {
                if (memberAdded.Properties.HasValues)
                {
                    // when the ChannelAccount object is fully a TeamsChannelAccount (when Teams changes the service to return the full details)
                    teamsMembersAdded.Add(JObject.FromObject(memberAdded).ToObject <TeamsChannelAccount>());
                }
                else
                {
                    // TODO: this code path is intended to be temporary and should be removed in 4.7/4.8 or whenever Teams is updated

                    // we have a simple ChannelAccount so will try to flesh out the details using the GetMembersAsync call
                    if (teamMembers == null)
                    {
                        var result = await TeamsInfo.GetMembersAsync(turnContext, cancellationToken).ConfigureAwait(false);

                        teamMembers = result.ToDictionary(teamsChannelAccount => teamsChannelAccount.Id, teamsChannelAccount => teamsChannelAccount);
                    }

                    if (teamMembers.TryGetValue(memberAdded.Id, out var value))
                    {
                        teamsMembersAdded.Add(value);
                    }
                    else
                    {
                        // unable to find the member added in ConversationUpdate Activity in the response from the GetMembersAsync call
                        var newTeamsChannelAccount = new TeamsChannelAccount
                        {
                            Id          = memberAdded.Id,
                            Name        = memberAdded.Name,
                            AadObjectId = memberAdded.AadObjectId,
                            Role        = memberAdded.Role
                        };

                        teamsMembersAdded.Add(newTeamsChannelAccount);
                    }
                }
            }

            await OnTeamsMembersAddedAsync(teamsMembersAdded, teamInfo, turnContext, cancellationToken).ConfigureAwait(false);
        }
        /// <summary>
        /// Override this in a derived class to provide logic for when members other than the bot
        /// join the channel, such as your bot's welcome logic.
        /// UseIt will get the associated members with the provided accounts.
        /// </summary>
        /// <param name="membersAdded">A list of all the accounts added to the channel, as
        /// described by the conversation update activity.</param>
        /// <param name="teamInfo">The team info object representing the team.</param>
        /// <param name="turnContext">A strongly-typed context object for this turn.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A task that represents the work queued to execute.</returns>
        protected virtual async Task OnTeamsMembersAddedDispatchAsync(IList <ChannelAccount> membersAdded, TeamInfo teamInfo, ITurnContext <IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
        {
            var teamsMembersAdded = new List <TeamsChannelAccount>();

            foreach (var memberAdded in membersAdded)
            {
                if (memberAdded.Properties.HasValues || memberAdded.Id == turnContext.Activity?.Recipient?.Id)
                {
                    // when the ChannelAccount object is fully a TeamsChannelAccount, or the bot (when Teams changes the service to return the full details)
                    teamsMembersAdded.Add(JObject.FromObject(memberAdded).ToObject <TeamsChannelAccount>());
                }
                else
                {
                    TeamsChannelAccount newMemberInfo = null;
                    try
                    {
                        newMemberInfo = await TeamsInfo.GetMemberAsync(turnContext, memberAdded.Id, cancellationToken).ConfigureAwait(false);
                    }
                    catch (ErrorResponseException ex)
                    {
                        if (ex.Body?.Error?.Code != "ConversationNotFound")
                        {
                            throw;
                        }

                        // unable to find the member added in ConversationUpdate Activity in the response from the GetMemberAsync call
                        newMemberInfo = new TeamsChannelAccount
                        {
                            Id          = memberAdded.Id,
                            Name        = memberAdded.Name,
                            AadObjectId = memberAdded.AadObjectId,
                            Role        = memberAdded.Role,
                        };
                    }

                    teamsMembersAdded.Add(newMemberInfo);
                }
            }

            await OnTeamsMembersAddedAsync(teamsMembersAdded, teamInfo, turnContext, cancellationToken).ConfigureAwait(false);
        }