Search code examples
botframework

How to start a new thread in channel with a Proactive Channel Dialog?


My bot can create a new thread in a channel like this. Now I want to start a proactive dialog in this new thread. I am starting the dialog in a subsequent ContinueConversationAsync callback. The dialog seems to start, but as soon as a user is prompted, the users reply is not handled by the dialog but the MainDialog.

If I initiate the dialog with a user sent activity, then the dialog handles prompts correctly. Only the proactive dialog does not seem to work in a newly created channel.

This is my code

var conversationParameters = new ConversationParameters
{
    IsGroup = true,
    ChannelData = new TeamsChannelData
    {
        Channel = new ChannelInfo(teamsChannelId)
    },
    Activity = (Activity)message
};

ConversationReference newConversationReference = null;
await adapter.CreateConversationAsync(
    teamsChannelId,
    serviceUrl,
    credentials,
    conversationParameters,
    (t, c) =>
    {
        newConversationReference = t.Activity.GetConversationReference();
        return Task.CompletedTask;
    }, cancellationToken);


await adapter.ContinueConversationAsync(
    _appId,
    newConversationReference,
    async (t, c) =>
    {
        var dialogStateAccessor = this.conversationState.CreateProperty<DialogState>(nameof(DialogState));
        var dialogState = await dialogStateAccessor.GetAsync(t, () => new DialogState());

        var dialogSet = new DialogSet(dialogStateAccessor);
        dialogSet.Add(dialog);
        var dialogContext = await dialogSet.CreateContextAsync(t, cancellationToken);
        await dialogContext.BeginDialogAsync(dialog.Id, options, cancellationToken);
        await conversationState.SaveChangesAsync(t, false, cancellationToken);
    },
    cancellationToken);

Any ideas?


Solution

  • My Problem was that I took the ConversationReference from the the callback of the newly created channel post and tried to use that in ContinueConverationAsync(). That ConversationReference however is not enough. So I merged my original ConversationReference with the new ConversationReference and used that instead. Now it works like a charm.

    Here is my updated code:

    ConversationReference newConversationReference = null;
    await adapter.CreateConversationAsync(
        conversationChannelId,
        serviceUrl,
        credentials,
        conversationParameters,
        (t, c) =>
        {
            newConversationReference = t.Activity.GetConversationReference();
            return Task.CompletedTask;
        }, cancellationToken);
    
    if (dialog != null)
    {
        // Proactive channel dialogs dont seem to work with the newConversationReference: responses to the dialog are handled by the MainDialog.
        // So I just create a new ConversationReference from the topic subscription and the new conversation. That works.
        var newNewConversationReference = new ConversationReference
        {
            ActivityId = newConversationReference.ActivityId,
            Bot = conversationReference.Bot,
            ChannelId = conversationReference.ChannelId,
            ServiceUrl = conversationReference.ServiceUrl,
            User = conversationReference.User,
            Conversation = new ConversationAccount
            {
                Id = newConversationReference.Conversation.Id,
                AadObjectId = conversationReference.Conversation.AadObjectId,
                ConversationType = conversationReference.Conversation.ConversationType,
                IsGroup = conversationReference.Conversation.IsGroup,
                Name = conversationReference.Conversation.Name,
                Properties = conversationReference.Conversation.Properties,
                TenantId = conversationReference.Conversation.TenantId,
                Role = conversationReference.Conversation.Role,
            },
        };
    
        await adapter.ContinueConversationAsync(
            _appId,
            newNewConversationReference,
            async (t, c) =>
            {
                var dialogStateAccessor = this.conversationState.CreateProperty<DialogState>(nameof(DialogState));
                var dialogState = await dialogStateAccessor.GetAsync(t, () => new DialogState());
    
                var dialogSet = new DialogSet(dialogStateAccessor);
                dialogSet.Add(dialog);
                var dialogContext = await dialogSet.CreateContextAsync(t, cancellationToken);
                await dialogContext.BeginDialogAsync(dialog.Id, options, cancellationToken);
                await conversationState.SaveChangesAsync(t, false, cancellationToken);
            },
            cancellationToken);
    }