Search code examples
botframeworkdirect-line-botframework

How to send an activity from a bot dialog (c#) trough direct line to a client (angular)


I'm trying to send an event activity from the bot to the client when I'm in a certain dialog, but I just can't get it to work... Any suggestions or code samples I can look at?

Also I already tried to make a back channel and it works but on the bot side as far as I could tell it only works in the message controller.

EDIT*

I'm sorry, for not providing any details, I was in a hurry last week.

So i'm making a bot that will fill a "report" for a user, the bot asks questions, and the user gives the answers. For the first question i have to call a function in my angular app when i'm in the first dialog, that is after the root dialog, that will check the user input and return an "Account" object to the bot if the account exists, if it doesn't then it returns null... (and i know it would be easier to just make an API and connect directly to the bot, but i have to use angular)

I'm using the back channel like so:

botConnection.activity$ .filter( activity => { // tslint:disable-next-line:max-line-length return (activity.type === 'message' && activity.from['id'] === 'VisitReportV3' && activity.text === 'Please select an account...') || (activity.type === 'message' && activity.from['id'] === 'user' && this.accountFlag) }) .subscribe(activity => { if (activity.from['id'] === 'VisitReportV3' && activity.text === 'Please select an account...') { console.log('"account" received'); this.accountFlag = true; postAccountInfo(); } else if (activity.from['id'] === 'user' && this.accountFlag) { console.log('"account" flag recieved'); this.accountFlag = false; } });

It's probably completely wrong but i didn't know how else to do it..

tl;dr:

So in short, i need to check if i'm in the first dialog (or the one that asks me for the account) and if I am then wait for the next user input and call the angular function to check the input and see if there are any accounts that match, if not return null if they do return the serialized object to the bot for some more processing... I hope this explains some more.


Solution

  • In your messages controller you are probably only forwarding activities with a type of Message to your dialogs. If you used the default bot template, you probably have something like

    public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
    {
        if (activity.GetActivityType() == ActivityTypes.Message)
        {
            await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
        }
        else
        {
            HandleSystemMessage(activity);
        }
        var response = Request.CreateResponse(HttpStatusCode.OK);
        return response;
    }
    

    that you need to change to

    public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
    {
        if (activity.GetActivityType() == ActivityTypes.Message || activity.GetActivityType() == ActivityTypes.Event)
        {
            await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
        }
        else
        {
            HandleSystemMessage(activity);
        }
        var response = Request.CreateResponse(HttpStatusCode.OK);
        return response;
    }
    

    That will send both messages and events to your dialogs. Keep in mind though that you need to check for both of them in each of you dialog methods now especially when you are expecting events as the user can type and send a message before your event gets sent.

    EDIT

    You can't get the dialog name from activity.from['id']. However, in your dialog you can create an Activity reply and set the name to be something else. For example in your dialog,

    private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
    {
        Activity activity = await result as Activity;
        Activity reply = activity.CreateReply();
        reply.Text = "Please select an account...";
        reply.Name = "VisitReportV3";
        await context.PostAsync(reply);
    }
    

    then in your back channel JavaScript you would change from checking if activity.from['id'] === "VisitReportV3" to activity.name === "VisitReportV3".