如何在嵌套对话框中处理状态并配置cosmos db存储? (bot framewrok v4)

时间:2019-07-17 10:57:37

标签: c# botframework

我正在尝试使用嵌套对话框构建聊天机器人,该对话框应该从用户那里收集信息并将其存储在Azure CosmosDB中。在我实现Cosmos DB存储之前,该对话框运行良好。现在,使用CosmosDB存储,对话框将在第一个对话框中的第一个任务上循环,而不是继续。我该如何解决这个问题?

从对话框开始,以及在实现CosmosDB存储之前的状态。我基本上遵循了此示例43.complex-dialog中的代码。

然后,实现存储,我以this answer为指导。我像这样在Startup.cs中设置cosmosDB存储:

public class Startup
    {

        private const string CosmosServiceEndpoint = "MyCosmosServiceEndpoint";
        private const string CosmosDBKey = "MyCosmosDBKey";
        private const string CosmosDBDatabaseName = "MyCosmosDBDatabaseName";
        private const string CosmosDBCollectionName = "MyCosmosDBCollectionName";
        private const string CosmosDBPartitionKey = "MyCosmosDBPartitionKey";
        
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;    
        }
        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            var storage = new CosmosDbStorage(new CosmosDbStorageOptions
            {
                AuthKey = CosmosDBKey,
                CollectionId = CosmosDBCollectionName,
                CosmosDBEndpoint = new Uri(CosmosServiceEndpoint),
                DatabaseId = CosmosDBDatabaseName,
                PartitionKey = CosmosDBPartitionKey
            });

            var conversationState = new ConversationState(storage);
            var userState = new UserState(storage);

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
            services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();
            services.AddSingleton<MainDialog>();
            services.AddTransient<IBot, WelcomeBot<MainDialog>>();
            services.AddSingleton<IStorage, MemoryStorage>();
            services.AddSingleton(userState);
            services.AddSingleton(conversationState);
            services.AddSingleton(userState.CreateProperty<UserProfile>("MyUserState"));
            services.AddSingleton(conversationState.CreateProperty<DialogState>("MyBotDialogState"));

        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            app.UseDefaultFiles();
            app.UseStaticFiles();

            app.UseMvc();
        }
    }
}

我的主要bot看起来像这样(不要管名称“ Echobot”):

public class EchoBot<T> : ActivityHandler where T : Dialog
    {
        private readonly BotState _userState;
        private readonly BotState _conversationState;
        private readonly Dialog _dialog;
        private readonly ILogger _logger;

        private readonly IStatePropertyAccessor<UserProfile> _userStateAccessor;
        private readonly IStatePropertyAccessor<DialogState> _conversationDialogStateAccessor;

        // Create cancellation token (used by Async Write operation).
        public CancellationToken CancellationToken { get; private set; }

        public EchoBot(ConversationState conversationState, UserState userState, T dialog, ILogger<EchoBot<T>> logger, IStatePropertyAccessor<UserProfile> userStatePropertyAccessor, IStatePropertyAccessor<DialogState> dialogStatePropertyAccessor) 
        {
            _conversationState = conversationState;
            _userState = userState;
            _dialog = dialog;
            _logger = logger;
            _userStateAccessor = userStatePropertyAccessor;
            _conversationDialogStateAccessor = dialogStatePropertyAccessor;

        }

        public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
        {
            await base.OnTurnAsync(turnContext, cancellationToken);

            var currentUserState = await _userStateAccessor.GetAsync(turnContext, () => new UserProfile(), cancellationToken);
            var currentConversationDialogState = await _conversationDialogStateAccessor.GetAsync(turnContext, () => new DialogState(), cancellationToken);

            await _userStateAccessor.SetAsync(turnContext, currentUserState, cancellationToken);
            await _conversationDialogStateAccessor.SetAsync(turnContext, currentConversationDialogState, cancellationToken);

            // Save any state changes that might have occured during the turn.
            await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
            await _userState.SaveChangesAsync(turnContext, false, cancellationToken);

            
        }

        protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken=default)
        {
            _logger.LogInformation("Running dialog with Message Activity.");
            //See DialogExtension.cs in the sample "complex-dialog" to see the Run method.
            await _dialog.Run(turnContext, _conversationDialogStateAccessor, cancellationToken);

        }
    }
}

1 个答案:

答案 0 :(得分:0)

现在,如果您从PartitionKey中删除了CosmosDbStorageOptions参数,它应该可以工作。由于您的容器当前已分区,您可能需要删除您的容器或使用其他名称。最简单的方法就是删除您的容器,然后让机器人为您创建一个容器。

提供了partitionKey时,所有Bot Builder SDK中目前都存在一个从分区数据库读取数据的错误。 Tracking the issue here