【问题标题】:The given key 'dialogs' was not present in the dictionary while using ContinueDialogAsync使用 ContinueDialogAsync 时字典中不存在给定键“对话框”
【发布时间】:2019-02-15 12:15:55
【问题描述】:

我正在使用 Bot Framework SDK v-4。我创建了几个继承自ComponentDialog 的对话框并覆盖了方法:BeginDialogAsyncContinueDialogAsync。下面是IBot的实现。

public class Bot : IBot
{
    private readonly BotAccessors _accessors;
    private readonly ILogger _logger;

    private DialogSet _dialogs = null;
    private string _botName = string.Empty;
    private IConfiguration _configuration = null;
    private UserDetail _userDetail = null;
    private ConversationData _conversationData = null;
    private IStatePropertyAccessor<TurnState> _turnStateAccessor = null;

    /// <summary>
    /// Initializes a new instance of the class.
    /// </summary>                        
    public Bot(BotAccessors accessors, ILoggerFactory loggerFactory, IConfiguration configuration)
    {
        _accessors = accessors ?? throw new System.ArgumentNullException(nameof(accessors));
        if (loggerFactory == null)
        {
            throw new System.ArgumentNullException(nameof(loggerFactory));
        }

        _configuration = configuration;
        _dialogs = new DialogSet(accessors.ConversationState.CreateProperty<DialogState>(nameof(DialogState)));
        _turnStateAccessor = accessors.TurnStateAccessor;
        _dialogs.Add(new GreetingDialog(_turnStateAccessor, loggerFactory, configuration));
        _dialogs.Add(new QnADialog(_turnStateAccessor, loggerFactory, configuration));
        _botName = configuration["BotName"];
        _logger = loggerFactory.CreateLogger<Bot>();
        _logger.LogTrace("Bot turn start.");
    }

    public override Task<DialogTurnResult> BeginDialogAsync(DialogContext outerDc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
    {
        _turnState = _turnStateAccessor.GetAsync(outerDc.Context).Result;
        outerDc.ContinueDialogAsync();
        return base.BeginDialogAsync(outerDc, options, cancellationToken);
    }

    public override Task<DialogTurnResult> ContinueDialogAsync(DialogContext outerDc, CancellationToken cancellationToken = default(CancellationToken))
    {
        _turnState = _turnStateAccessor.GetAsync(outerDc.Context).Result;

        //some code
        _turnStateAccessor.SetAsync(outerDc.Context, _turnState).ConfigureAwait(false);
        return base.ContinueDialogAsync(outerDc, cancellationToken);
    }

}

我从 Bot 的 OnTurnAsync 方法调用对话框,如下所示:await dialogContext.BeginDialogAsync(nameof(GreetingDialog)).ConfigureAwait(false);。它到达我的对话框的BeginDialogAsync 方法,然后继续到ContinueDialogAsync。它工作正常,但是,当从该方法返回(使用base.ContinueDialogAsync(outerDc, cancellationToken);)时,我得到了一些我从 Visual Studio 的诊断工具中捕获的异常。

另外,我将异常作为活动消息发送到客户端(机器人框架模拟器),如下所示。

抱歉,好像出了点问题。例外: System.ArgumentNullException:值不能为空。参数名称: 对话框 ID 在 Microsoft.Bot.Builder.Dialogs.DialogContext.BeginDialogAsync(字符串 dialogId, 对象选项, CancellationToken cancelToken) in D:\a\1\s\libraries\Microsoft.Bot.Builder.Dialogs\DialogContext.cs:line 84 在 Microsoft.Bot.Builder.Dialogs.ComponentDialog.BeginDialogAsync(DialogContext outerDc, 对象选项, CancellationToken cancelToken) in D:\a\1\s\libraries\Microsoft.Bot.Builder.Dialogs\ComponentDialog.cs:line 59 在 Microsoft.Bot.Builder.Dialogs.DialogContext.BeginDialogAsync(字符串 dialogId, 对象选项, CancellationToken cancelToken) in D:\a\1\s\libraries\Microsoft.Bot.Builder.Dialogs\DialogContext.cs:line 84 在 Chatbot.Bot.OnTurnAsync(ITurnContext turnContext, CancellationToken 取消令牌)在 C:\GIS\ChatbotNew\Chatbot\Chatbot\Bot.cs:第 120 行 Microsoft.Bot.Builder.MiddlewareSet.ReceiveActivityWithStatusAsync(ITurnContext turnContext、BotCallbackHandler 回调、CancellationToken 取消令牌)在 D:\a\1\s\libraries\Microsoft.Bot.Builder\MiddlewareSet.cs:第 55 行 Microsoft.Bot.Builder.BotAdapter.RunPipelineAsync(ITurnContext turnContext、BotCallbackHandler 回调、CancellationToken 取消令牌)在 D:\a\1\s\libraries\Microsoft.Bot.Builder\BotAdapter.cs:167 行

Update-1

根据 Drew 的回答,我删除了 outerDc.ContinueDialogAsync();,但在单步执行 BeginDialogAsync 函数中的 return base.BeginDialogAsync(outerDc, options, cancellationToken); 时出现了一些错误(如下所示)。

另外,在单步执行OnTurnAsync 函数时,我在尝试获取BotState 时遇到错误,如下所示。

TurnState 实现:

public class TurnState
{
    public int TurnCount { get; set; } = 0;
    public string BotType { get; set; } = string.Empty;
    public string ConversationLanguage { get; set; } = string.Empty;
    //other properties...
}

在尝试创建 DialogContext 时也出现类似错误。

ConfigureServices 在 Startup.cs 中:

public void ConfigureServices(IServiceCollection services)
{
    services.AddBot<Bot>(options =>
   {
       var secretKey = Configuration.GetSection("botFileSecret")?.Value;

        // Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection.
        var botConfig = BotConfiguration.Load(@".\Chatbot.bot", secretKey);
       services.AddSingleton(sp => botConfig);

        // Retrieve current endpoint.
        var service = botConfig.Services.Where(s => s.Type == "endpoint" && s.Name == "development").FirstOrDefault();
       if (!(service is EndpointService endpointService))
       {
           throw new InvalidOperationException($"The .bot file does not contain a development endpoint.");
       }

       //options.CredentialProvider = new SimpleCredentialProvider(Configuration[MicrosoftAppCredentials.MicrosoftAppIdKey], Configuration[MicrosoftAppCredentials.MicrosoftAppPasswordKey]);
       options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);


       // Creates a logger for the application
       ILogger logger = _loggerFactory.CreateLogger<Bot>();

        // Catches any errors that occur during a conversation turn and logs them.
        options.OnTurnError = async (context, exception) =>
       {
           await context.SendActivityAsync("Sorry, it looks like something went wrong. Exception: " + exception);
       };

       // The Memory Storage used here is for local bot debugging only. When the bot
       // is restarted, everything stored in memory will be gone.
       IStorage dataStore = new MemoryStorage();

       var conversationState = new ConversationState(dataStore);

       options.State.Add(conversationState);

   });

    // Create and register state accesssors.
    // Acessors created here are passed into the IBot-derived class on every turn.
    services.AddSingleton<BotAccessors>(sp =>
    {
        var options = sp.GetRequiredService<IOptions<BotFrameworkOptions>>().Value;
        if (options == null)
        {
            throw new InvalidOperationException("BotFrameworkOptions must be configured prior to setting up the state accessors");
        }

        var conversationState = options.State.OfType<ConversationState>().FirstOrDefault();
        if (conversationState == null)
        {
            throw new InvalidOperationException("ConversationState must be defined and added before adding conversation-scoped state accessors.");
        }

        // Create the custom state accessor.
        // State accessors enable other components to read and write individual properties of state.
        var accessors = new BotAccessors(conversationState)
        {
            TurnStateAccessor = conversationState.CreateProperty<TurnState>(BotAccessors.TurnStateName),
        };

        return accessors;
    });
}

有什么帮助吗?

【问题讨论】:

    标签: c# botframework azure-bot-service


    【解决方案1】:

    我正试图完全理解您在这里期望发生的事情:

    public override Task<DialogTurnResult> BeginDialogAsync(DialogContext outerDc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
    {
        _turnState = _turnStateAccessor.GetAsync(outerDc.Context).Result;
        outerDc.ContinueDialogAsync();
        return base.BeginDialogAsync(outerDc, options, cancellationToken);
    }
    

    具体来说,你为什么在这里打电话给outerDc.ContinueDialogAsync()?这基本上是将对话框堆叠在一起。如果您删除了该行,那么您在此处显示的所有其他内容都应该可以正常工作。

    如果您通过调用来更新您的问题,详细说明您正在尝试完成什么,我会很乐意更新我的答案,尝试让您走上完成任何可能的正确道路。

    【讨论】:

    • 感谢您的回复。如果不调用outerDc.ContinueDialogAsync()ContinueDialogAsync 函数就不会被执行。我在 SDK v-4 的预发布版本中使用了这种方法,所以想这样做。更新问题中的更多详细信息。
    • 只是一个更新,我还研究了这里提到的解决方案:github.com/Microsoft/BotBuilder-Samples/issues/1080。我仍然遇到同样的问题。
    • 我仍然不太明白这里的期望是什么,但我可以告诉你这行不通。这里的outerDcDialogContext,您的自定义ComponentDialog 刚刚由其他人调用BeginDialogAsync("yourDialogId", ...) 启动。通过调用outerDc.ContinueDialogAsync(),你实际上是在告诉DialogContext 继续你自己,你在你自己的“开始”阶段这样做。 TL;DR:你跨越了生命周期事件。如果你有需要在“开始”和“继续”中发生的逻辑,那么你应该重构一个辅助方法并从两者中调用它。
    • 我上面描述的问题不仅仅是outerDcContinueDialogAsync。我在尝试获取 BotState 时遇到错误。创建DialogContext 时我也遇到错误。这些发生在对话更新/消息事件期间的OnTurnAsync 内。
    猜你喜欢
    • 2012-02-18
    • 2022-09-28
    • 2016-08-14
    • 2019-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多