context.Wait <t>()和context.Wait()混淆

时间:2017-06-03 16:33:01

标签: c# botframework

Bot框架发生了一些令人悲伤而不是微笑的事情。

采用以下示例:

public async Task StartAsync(IDialogContext context)
{            
    _userName    = context.FindUserName();
    _packageId   = context.FindPackageId();

    if(!string.IsNullOrEmpty(_packageId))
    {
        context.Call(new ConfirmPackageIdResuse(_packageId), AfterConfirmIdReuseAsync);
    }
    else
    {
        context.Call(new AskForPackageIdDialog(), DisplayPackageStatusAsync);
    }
    await Task.CompletedTask;
}

此启动任务位于基础LuisDialog中从多个方法调用的类ObtainPackageIdDialog:IDialog 中。 packageId 用于跟踪包裹,更改地址,更改交货时间等。

流程如下:

  • LuisDialog执行CALL以获取包ID
  • ObtainPackageId要么
    • 调用ConfirmPackageResue
    • 调用AskForPackageIdDialog

现在,如果上下文中存在packageId(存储在 ConversationData 中),那么机器人会询问用户是否要使用它( ConfirmPackageIdReuse )或者如果他想输入新的包ID( AskForPackageIdDialog )。

后者看起来像这样:

[Serializable]
public class AskForPackageIdDialog : IDialog<string>
{
    public async Task StartAsync(IDialogContext context)
    {
        await context.PostAsync("Type in the package id:");
        context.Wait(MessageReceivedAsync);
    }


    public async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
    {
        var candidate = (await result).Text;
        var validator = WebApiApplication.IoCResolver.GetInstance<IPackageValidator>();

        if(validator.IsValidId(candidate))
        {
            context.SetPackageId(candidate);
            context.Done(candidate);
        }
        else
        {
            context.Wait(MessageReceivedAsync);
        }
    }
}

让我疯狂1

AskForPackageIdDialog 中的 MessageReceivedAsync()立即执行,无需等待。没有例外。

让我疯了2

由于 MessageReceivedAsync()立即执行,因此结果中没有有效的packageId,因此 else 语句会启动。问题是,它不是在 AskForPackageIdDialog 中更长,但是在对话框堆栈中调用它的类中。

让我疯狂3

AskForPackageIdDialog 的声明中可以看出,它是 IDialog&lt; string&gt; ,因此下面的对话框将通过以下方法恢复:

private async Task DisplayPackageStatusAsync(IDialogContext context, IAwaitable<string> result)

然而,在这里,它崩溃,声称它收到 IAwaitable&lt; MessageActivity&gt; ,即使关闭对话框类型IDialog。

我已经一遍又一遍地阅读了关于机器人框架的文档,我无法理解为什么这对我失败了。关于我可能做错的任何意见将不胜感激。

  

观察
  它看起来像底层LUISDialog可能是责备在这里,我可以告诉它它确实填写activity.text,这是在堆栈上出现2个对话框。该属性是get / set,我已经尝试通过将其显式设置为string.Empty来清除它,但它仍然使用活动文本到达2个堆栈,使得Intent命中。

我有一个理论, context.Call()似乎是从我的LUIS对话框中执行 context.Forward(),因为activity.Text具有原始的用户文字。然后通过立即调用MessageReceivedAsync抛出我的其他对话框。如果是这种情况,如何在进行呼叫之前正确重置context.Activity?

最后,问题

基于以上和我的理论,这个可以解释为什么我从 context.Call&lt; string&gt;() context.Call得到混合回复()即可。有人可以向我确认是这样的吗?在开发期间,我看到了很多关于错误类型的 IAwaitable 的例外,没有明显的解释。

我在StackOverflow上发现了一个问题,表明僵尸框架现在自动使用上次使用的 context.Wait 方法,以避免过多的样板,但我相信这可能是我的根源现在悲伤,肯定会引起很多困惑。

**请求评论:**

   [Serializable]
    public class LuisRoot : LuisDialog<object>
    {
        public LuisRoot(ISettingsReader settings)
            : base(new LuisService(new LuisModelAttribute(settings["luis.modelid"], settings["luis.subscriptionkey"])))
        {            
        }


[LuisIntent("None")]
public async Task None(IDialogContext context, LuisResult result)
{
    await context.PostAsync("Oh, I'm sorry, but I have no idea what you just said!");
    context.Wait(MessageReceived);
}

    [LuisIntent("Track package")]
    public async Task TrackPackageAsync(IDialogContext context, LuisResult result)
    {
        await Task.CompletedTask;            
        context.ConversationData.SetValue("LuisResult", result);
        context.Call(new GetPackageId(), AfterPackageIdForTrackingStatus);            
    }


    private async Task AfterPackageIdForTrackingStatus(IDialogContext context, IAwaitable<string> result)
    {
        var packageId = await result;

        if (!string.IsNullOrEmpty(packageId))
        {
            context.Call<object>(new DisplayPackageStatus(packageId), AfterDisplayPackageStatus);
        }
        else
        {
            await context.PostAsync("I'm sorry, but I cannot help you without a valid tracking Id.");                
        }            
    }

**最后,MessagesController.Post()**

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

0 个答案:

没有答案