我正在将botBuilder SDK 4.3用于Node js。
我在对话框的构造函数中创建了一个sessionState属性。 在某些对话框步骤中,我为该属性设置了一个值。
在另一步骤中,我试图在setTimeOut之类的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);
}
}
超时结束后,出现此错误,notif
为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.
任何解决方案吗?
答案 0 :(得分:4)
由于某种原因,BotFramework无法与回调一起很好地工作,这就是为什么您收到“无法对已撤销的代理执行'get'的操作”错误的原因。解决此问题的方法(但很复杂)是创建一个主动消息API端点,从超时回调中对其调用一个请求,然后从该主动消息中执行其余的机器人程序调用。我建议在开始下面的代码之前,先看一下Proactive Messaging示例。
index.js文件
我们将向我们的Restify服务器添加一个/ api / notify终结点,该终结点将在超时结束时被点击。我建议向您的机器人添加一种方法来处理发送主动消息,这样您就可以保留机器人中包含的所有状态和对话框元素,而不必将它们提升为索引文件。请注意,您必须将适配器作为参数传递给您的机器人。
let bot = new Bot(adapter, conversationState, userState);
...
server.get('/api/notify/:conversationId', (req, res) => {
bot.sendProactiveMessages(req.params.conversationId);
res.send(204);
});
对话框
在对话框的此步骤中,我们将响应的属性添加到用户个人资料-您也可以将其添加到对话状态-并将默认值设置为false。然后,无需配置回调来访问状态并向用户发送消息,只需使用HTTP客户端(例如Axios或Request)向会话步骤中作为我们在上一步中创建的端点的URL参数发出一个get请求,并将会话ID作为URL参数。>
当用户响应下一个提示时,将响应值更新为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);
}
});
}
}
对于一个简单的操作,我知道这有点复杂,但是我希望这会有所帮助!
答案 1 :(得分:0)
使用Promise解决了此问题,我只是将timeOut移到了另一个函数中。
async partialNotify(step) {
return new Promise(async resolve => {
setTimeout(async () => {
const notif = await this.reservationNotifProp.get(step.context);
if (notif) {
console.log("Send Notif ...");
}
}, 50000);
resolve(true);
});
}
答案 2 :(得分:-1)
请检查对话状态是否已在index.js
中声明,如下所示。
const conversationState = new ConversationState(memmoryStorage);