当用户响应下一个提示时,将响应值更新为true,这样我们就可以判断用户是否从主动消息中响应了.async captureName(step) { const profile = await this.profileAccessor.get(step.context); profile.name = step.result; profile.responded = false; this.profileAccessor.set(step.context, profile); const { conversation: { id }} = TurnContext.getConversationReference(step.context.activity); setTimeout(() => { axios.get(`http://localhost:3978/api/notify/${id}`) .then(() => {}) .catch(error => console.log(error)); }, 60000); return await step.next();}async promptForCity(step) { return await step.prompt(CITY_PROMPT, "What city are your from?");}async captureCity(step) { const profile = await this.profileAccessor.get(step.context); profile.city = step.result; profile.responded = true; this.profileAccessor.set(step.context, profile); return await step.next();} 启动在主动消息传递示例中,所有对话引用都存储在一个对象中.我们可以使用get请求中的对话ID作为键值来检索对话引用,并使用该引用继续对话.通过主动消息,您可以发送活动,访问和更新状态,取消对话框以及您可以使用漫游器执行的所有其他正常功能.class Bot extends ActivityHandler{ constructor(adapter, conversationState, userState) { super(); this.adapter = adapter; this.conversationReferences = {}; this.conversationState = conversationState; this.userState = userState; // Configure properties this.profileAccessor = this.userState.createProperty(USER_PROFILE); this.dialogState = this.conversationState.createProperty(DIALOG_STATE); } async sendProactiveMessages(conversationId) { const conversationReference = this.conversationReferences[conversationId]; conversationReference && await this.adapter.continueConversation(conversationReference, async context => { const { responded } = await this.profileAccessor.get(context); if (!responded) { const dc = await this.dialogs.createContext(context); await dc.cancelAllDialogs(); await context.sendActivity('Sorry you took too long to respond..'); await this.conversationState.saveChanges(context); } }); }}对于一个简单的操作,我知道这有点复杂,但是我希望这会有所帮助!I am using botBuilder SDK 4.3 for Node js.I created a conversationState property inside the constructor of a dialog.In some of the dialog steps I set a value to that property.In an other step, I tried to get the value of that property inside a setTimeOut like So.// Imports ...class Reservation extends ComponentDialog { constructor(id, conversationState, userState, dialogProps) { super(id); this.id = id; this.conversationState = conversationState; this.userState = userState; this.initialDialogId = CONFIGS.MAIN_DIALOG_ID; this.reservationNotifProp = conversationState.createProperty( "reservationNotif" ); ... this.addDialog( new WaterfallDialog(this.initialDialogId, [ this.askCheckIn.bind(this), this.askCheckout.bind(this) this.askNights.bind(this), this.validateDates.bind(this), ..... ] ); } async askCheckIn (step) { ... } async askCheckout (step) { ... } async askNights (step) { // ... this.reservationNotifProp.set(step.context, false); await this.conversationState.saveChanges(step.context); const ref = this; setTimeout(async () => { const notif = await this.reservationNotifProp.get(step.context); if (notif) { console.log("Send Notif ..."); } }, 50000); } async validateDates(step) { // ... this.reservationNotifProp.set(step.context, true); await this.conversationState.saveChanges(step.context); }}When the time out is finished, I got this error and notif is undefined:(node:47504) UnhandledPromiseRejectionWarning: TypeError: Cannot perform 'get' on a proxy that has been revoked at ConversationState.load (c:\Users\Montacer\Desktop\qt-bot\node_modules\botbuilder\node_modules\botbuilder-core\src\botState.ts:84:48) at BotStatePropertyAccessor.get (c:\Users\Montacer\Desktop\qt-bot\node_modules\botbuilder\node_modules\botbuilder-core\src\botStatePropertyAccessor.ts:97:43) at Timeout.setTimeout [as _onTimeout] (c:\Users\Montacer\Desktop\qt-bot\dialogs\reservation.js:366:63) at ontimeout (timers.js:498:11) at tryOnTimeout (timers.js:323:5) at Timer.listOnTimeout (timers.js:290:5)warning.js:18(node:47504) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)warning.js:18(node:47504) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.Any solutions ? 解决方案 For some reason, the BotFramework does not work well with callbacks which is why you are getting the "Cannot perform 'get' on a proxy that has been revoked" error. A solution - yet complicated - to this is to create a proactive message API endpoint, call a request to it from the timeout callback, and then execute the rest of the bot calls from the proactive message. I would recommend taking a look at the Proactive Messaging Sample before getting started with code below.index.js fileWe are going to add an /api/notify endpoint to our Restify Server that will be hit when the timeout finishes. I would recommend adding a method to your bot to handle sending proactive messages, so you can keep all of the state and dialog elements contained in your bot instead of elevating them to the index file. Note, you will have to pass the adapter as a parameter to your bot. let bot = new Bot(adapter, conversationState, userState);...server.get('/api/notify/:conversationId', (req, res) => { bot.sendProactiveMessages(req.params.conversationId); res.send(204);});DialogIn this step of the dialog, we are adding a responded attribute to the user profile - you can also add this to conversation state - and setting the default value to false. Then instead of configuring the callback to access the state and message the user, simply use an HTTP client like Axios or Request to make a get request with the conversation id as a URL parameter to the endpoint we just created in the step above.When the user responds to the next prompt, update the responded value to true so we can tell if the user responded from the proactive message.async captureName(step) { const profile = await this.profileAccessor.get(step.context); profile.name = step.result; profile.responded = false; this.profileAccessor.set(step.context, profile); const { conversation: { id }} = TurnContext.getConversationReference(step.context.activity); setTimeout(() => { axios.get(`http://localhost:3978/api/notify/${id}`) .then(() => {}) .catch(error => console.log(error)); }, 60000); return await step.next();}async promptForCity(step) { return await step.prompt(CITY_PROMPT, "What city are your from?");}async captureCity(step) { const profile = await this.profileAccessor.get(step.context); profile.city = step.result; profile.responded = true; this.profileAccessor.set(step.context, profile); return await step.next();}BotIn the proactive messaging sample, all of the conversation references are stored in an object. We can use the conversation id from the get request as the key value to retrieve the conversation reference and use the reference to continue the conversation. From the proactive message, you can send activities, access and update state, cancel dialogs, and all of the other normal functions you can do with a bot.class Bot extends ActivityHandler{ constructor(adapter, conversationState, userState) { super(); this.adapter = adapter; this.conversationReferences = {}; this.conversationState = conversationState; this.userState = userState; // Configure properties this.profileAccessor = this.userState.createProperty(USER_PROFILE); this.dialogState = this.conversationState.createProperty(DIALOG_STATE); } async sendProactiveMessages(conversationId) { const conversationReference = this.conversationReferences[conversationId]; conversationReference && await this.adapter.continueConversation(conversationReference, async context => { const { responded } = await this.profileAccessor.get(context); if (!responded) { const dc = await this.dialogs.createContext(context); await dc.cancelAllDialogs(); await context.sendActivity('Sorry you took too long to respond..'); await this.conversationState.saveChanges(context); } }); }}I know this a bit complicated for a simple action, but I hope this helps! 这篇关于无法在setTimeOut中获取对话状态属性值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!