We have welcome examples using OnMembersAddedAsync method but no examples showing how to handle user leaving conversation. I tried to override OnMembersRemovedAsync but it does not seem to be invoked (at least when I use bot framework emulator).
I need to do some cleanup at the event of user leaving/left conversation. An example or any tips would be appreciated.
Update: I'm using C# and Bot framework v4
This is going to be channel specific as it is dependent on the channel providing a feature that sends an update when the user leaves a conversation. Any other channels, you will need to research.
For Facebook, I was unable to find a scope that covers such an action. These are the available scopes which you can reference more closely here:
Web Chat, as a feature, also does not include this. However, given this is a web page, you can utilize the onbeforeunload()
window function to dispatch an event. The event listener will make use of Web Chat's store to dispatch either a message or event to the bot. For the sake of clarity, I'm sending different types of data via SEND_MESSAGE
and SEND_EVENT
.
const store = window.WebChat.createStore( {}, ( { dispatch } ) => next => async action => {
return next( action );
};
window.addEventListener( 'sendEventActivity', ( { data } ) => {
store.dispatch({
type: 'WEB_CHAT/SEND_MESSAGE',
payload: {
text: data
}
} )
,
store.dispatch( {
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'user_event',
value: {
name: 'end_conversation',
value: 'user ended conversation'
},
text: 'The user has left the conversation.'
}
} )
} );
window.onbeforeunload = function() {
const eventSendActivity = new Event( 'sendEventActivity' );
eventSendActivity.data = 'User left conversation';
window.dispatchEvent( eventSendActivity );
}
{ type: 'message',
id: '4uPdpZhlTFfBMziBE7EmEI-f|0000004',
timestamp: 2020-01-10T18:21:26.767Z,
serviceUrl: 'https://directline.botframework.com/',
channelId: 'directline',
from: { id: 'dl_123', name: 'johndoe', role: 'user' },
conversation: { id: '4uPdpZhlTFfBMziBE7EmEI-f' },
recipient: { id: 'botberg@QaeuoeEamLg', name: 'Dungeon Runner' },
textFormat: 'plain',
locale: 'en-US',
text: 'User left conversation',
channelData:
{ clientActivityID: '15786804807910gegwkp2kai',
clientTimestamp: '2020-01-10T18:21:20.792Z' }
}
{ type: 'event',
id: '4uPdpZhlTFfBMziBE7EmEI-f|0000005',
timestamp: 2020-01-10T18:21:26.780Z,
serviceUrl: 'https://directline.botframework.com/',
channelId: 'directline',
from: { id: 'dl_123', name: 'johndoe', role: 'user' },
conversation: { id: '4uPdpZhlTFfBMziBE7EmEI-f' },
recipient: { id: 'botberg@QaeuoeEamLg', name: 'Dungeon Runner' },
locale: 'en-US',
channelData:
{ clientActivityID: '1578680480821h7kgfm9cyz',
clientTimestamp: '2020-01-10T18:21:20.821Z' },
value:
{ name: 'end_conversation', value: 'user ended conversation' },
name: 'user_event'
}
Hope of help!
As Chrome, and other browsers, disallow blocking / delaying the closing of a window during onbeforeunload()
, sending an event using an event handler or listener is usually unreliable, at best. At worst, it just doesn't work.
However, there is another method that does appear work by using 'window.navigator.sendBeacon()' (providing it's supported).
sendBeacon is a low-level, simplified version of fetch that “asynchronously sends a small amount of data over HTTP to a web server”. It only sends as a POST, only takes the URL or URL + data as properties, and doesn’t wait for a response. As the docs state:
In testing, I have coupled it with a proactive messaging endpoint in my bot and it appears to work perfectly. (My code sample below is in JS, pulled from a project - for reference, here is the proactive messaging C# sample, available in other languages, as well).
When I navigate to another page or close the browser, sendBeacon posts the message to the endpoint creating the proactive message, which, in turn, sends an activity to the bot. When I return to the Web Chat page, the message is now visible in the chat window. Keep in mind, I also have persistence set up in Web Chat allowing me to return to a conversation previously started.
In the below image, I demo loading Web Chat, navigating to my browser’s home page, and then return – the proactive message is now visible in the chat.
(Web Chat) hosting page:
window.onbeforeunload = () => {
let body = { user: { userName: 'McUser', userId: 'abc123' } };
const headers = { type: 'application/json', 'Access-Control-Allow-Origin': '*' };
const blob = new Blob( [ JSON.stringify( body ) ], headers )
navigator.sendBeacon( 'http://localhost:3978/api/notify', blob )
}
Bot's proactive messaging endpoint:
server.post('/api/notify', async (req, res) => {
const userName = req.body.user.userName;
const userId = req.body.user.userId;
for (const conversationReference of Object.values(conversationReferences)) {
await adapter.continueConversation(conversationReference, async (turnContext) => {
await turnContext.sendActivity(`${ userName } (userId: ${ userId }) exited chat.`);
});
}
});