Skip to content Skip to sidebar Skip to footer

Userstate Showing Null In Onmembersadded Function

I have logic in my onMembersAdded function to load the user state and see if userData.accountNumber attribute exists. If it does not, a run an auth dialog to get the user's account

Solution 1:

If you want your bot to receive a conversation update from Web Chat with the correct user ID before the user sends a message manually, you have two options:

  1. Instead of connecting to Direct Line with a secret, connect with a token (recommended). Note that this will only work if you provide a user property in the body of your Generate Token request.
  2. Have Web Chat send an initial activity to the bot automatically so the user doesn't have to. This would be in response to DIRECT_LINE/CONNECT_FULFILLED, and it could be an invisible event activity so to the user it still looks like the first activity in the conversation came from the bot.

If you go with option 1, your bot will receive one conversation update with both the bot and the user in membersAdded, and the from ID of the activity will be the user ID. This is ideal because it means you will be able to acess user state.

If you go with option 2, your bot will receive two conversation update activities. The first is the one you're receiving now, and the second is the one with the user ID that you need. The funny thing about that first conversation update is that the from ID is the conversation ID rather than the bot ID. I presume this was an attempt on Web Chat's part to get the bot to mistake it for the user being added, since Bot Framework bots typically recognize that conversation update by checking if the from ID is different from the member being added. Unfortunately this can result in two welcome messages being sent because it's harder to tell which conversation update to respond to.

Conversation updates have been historically unreliable in Web Chat, as evidenced by a series of GitHub issues. Since you may end up having to write channel-aware bot code anyway, you might consider having the bot respond to a backchannel event instead of a conversation update when it detects that the channel is Web Chat. This is similar to option 2 but you'd have your bot actually respond to that event rather than the conversation update that got sent because of the event.

Solution 2:

Per Kyle's answer, I was able to resolve the issue. However, the documentation on initiating a chat session via tokens wasn't entirely clear, so I wanted to provide some guidance for others trying to solve this same issue.

First, you need to create an endpoint in your bot to generate the token. The reason I initiated the session from SECRET initially was because I didn't see a point to creating a token when the SECRET was exposed anyway to generate it. What wasn't made clear in the documentation was that you should create a separate endpoint so that the SECRET isn't in the browser code. You can/should further obfuscate the SECRET using environmental variables or key vault. Here is the code for the endpoint I set up (I'm passing in userId from browser, which you'll see in a minute).

server.post('/directline/token', async (req, res) => {

    try {
        var body = {User:{Id:req.body.userId}};
        const response = awaitrequest({
            url: 'https://directline.botframework.com/v3/directline/tokens/generate',
            method: 'POST',
            headers: { Authorization: `Bearer ${process.env.DIRECTLINE_SECRET}`},
            json: body,
            rejectUnauthorized: false
        });
        const token = response.token;
        res.setHeader('Content-Type', 'text/plain');
        res.writeHead(200);
        res.write(token);
        res.end();
    } catch(err) {
        console.log(err);
        res.setHeader('Content-Type', 'text/plain');
        res.writeHead(500);
        res.write('Call to retrieve token from Direct Line failed');
        res.end();
    }
})

You could return JSON here, but I chose to return token only as text. Now to call the function, you'll need to hit this endpoint from the script wherever you are deploying the bot (this is assuming you are using botframework-webchat CDN). Here is the code I used for that.

const response = awaitfetch('https://YOURAPPSERVICE.azurewebsites.net/directline/token', {
        method: 'POST',
        headers: {'Content-Type':'application/json'},
        body: JSON.stringify({userId:userID})
    });
    const token = await response.text();

Body of request must be stringified JSON. Fetch returns the response as a stream, so you need to convert it using .text() or .json() depending on how you are sending the response from your bot endpoint (I used .text()). You need to await both the fetchAND the response.text(). My whole script to deploy the webchat is within an async function. Just a note, if you need this to work in IE11 as I do, async/await won't work. I dealt with this by running the entire code through Babel once I was done and it seems to work fine.

Post a Comment for "Userstate Showing Null In Onmembersadded Function"