【问题标题】:Cosmos, retrieving conversation data within MessageControllerCosmos,在 MessageController 中检索对话数据
【发布时间】:2018-03-04 11:34:48
【问题描述】:

我正在尝试用 Azure 提供的 Cosmos 存储替换 InMemory 存储。

我在对话数据中存储了一些信息,在我的对话中使用它,如果发送了某个命令,我会从我的消息控制器中重置它。

我在对话中访问对话数据的方式是:

context.ConversationData.GetValueOrDefault<String>("varName", "");

我在 messageContoller 中重置数据的方式是:

StateClient stateClient = activity.GetStateClient();
BotData userData = await stateClient.BotState.GetConversationDataAsync(activity.ChannelId, activity.Conversation.Id);
userData.RemoveProperty("varName");
await stateClient.BotState.SetConversationDataAsync(activity.ChannelId, 
activity.Conversation.Id, userData);

如果我使用 InMemory,前一行代码可以正常工作。一旦我切换到 cosmos,代码的重置部分就会失败。在调试问题时,我发现返回的对话数据对象与从对话框中返回的对象不同,我无法重置变量。

这是我连接到 cosmos 数据库的方式:

var uri = new Uri(ConfigurationManager.AppSettings["DocumentDbUrl"]);
var key = ConfigurationManager.AppSettings["DocumentDbKey"];
var store = new DocumentDbBotDataStore(uri, key);

Conversation.UpdateContainer(
builder = >{
    builder.Register(c = >store).Keyed < IBotDataStore < BotData >> (AzureModule.Key_DataStore).AsSelf().SingleInstance();

    builder.Register(c = >new CachingBotDataStore(store, CachingBotDataStoreConsistencyPolicy.ETagBasedConsistency)).As < IBotDataStore < BotData >> ().AsSelf().InstancePerLifetimeScope();

});

知道为什么会这样吗?

编辑:

当使用 im 内存存储时,此代码可以正常工作,但用 cosmos 存储替换存储无法检索对话框外的对话数据(对话框正确获取/设置对话数据,但 StateClents 无法检索数据正确它返回一个空对象,但奇怪的是它与从对话框返回的会话 ID 相同)

【问题讨论】:

    标签: c# botframework azure-cosmosdb


    【解决方案1】:

    在调试问题时,我发现返回的对话数据对象与从对话框中返回的对象不同,我无法重置变量。

    请确保您在保存数据和重置数据操作时使用相同的对话。

    此外,我使用以下示例代码进行了测试,我可以按预期保存和重置对话数据。

    在消息控制器中:

    public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
    {
        if (activity.Type == ActivityTypes.Message)
        {
            if (activity.Text=="reset")
            {
                var message = activity as IMessageActivity;
    
                using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
                {
                    var botDataStore = scope.Resolve<IBotDataStore<BotData>>();
                    var key = new AddressKey()
                    {
                        BotId = message.Recipient.Id,
                        ChannelId = message.ChannelId,
                        UserId = message.From.Id,
                        ConversationId = message.Conversation.Id,
                        ServiceUrl = message.ServiceUrl
                    };
                    var userData = await botDataStore.LoadAsync(key, BotStoreType.BotConversationData, CancellationToken.None);
    
                    //var varName = userData.GetProperty<string>("varName");
    
                    userData.SetProperty<object>("varName", null);
    
                    await botDataStore.SaveAsync(key, BotStoreType.BotConversationData, userData, CancellationToken.None);
                    await botDataStore.FlushAsync(key, CancellationToken.None);
                }
            }
    
            await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
        }
        else
        {
            HandleSystemMessage(activity);
        }
        var response = Request.CreateResponse(HttpStatusCode.OK);
        return response;
    }
    
    public class AddressKey : IAddress
    {
        public string BotId { get; set; }
        public string ChannelId { get; set; }
        public string ConversationId { get; set; }
        public string ServiceUrl { get; set; }
        public string UserId { get; set; }
    }
    

    在对话框中:

    private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
    {
        var activity = await result as Activity;
    
        // calculate something for us to return
        int length = (activity.Text ?? string.Empty).Length;
    
        var varName = "";
    
        if (activity.Text.ToLower().Contains("hello"))
        {
            context.ConversationData.SetValue<string>("varName", activity.Text);
        }
    
        if (activity.Text.ToLower().Contains("getval"))
        {
            varName = context.ConversationData.GetValueOrDefault<string>("varName", "");
    
            activity.Text = $"{varName} form cosmos";
        }
    
        if (activity.Text.ToLower().Contains("remove"))
        {
            activity.Text = "varName is removed";
        }
    
        // return our reply to the user
        await context.PostAsync($"{activity.Text}");
    
        context.Wait(MessageReceivedAsync);
    }
    

    测试步骤:

    输入hello bot后,可以在Cosmosdb中找到已保存为对话数据。

    输入“reset”后,可以发现varName的值被重置为null

    【讨论】:

    • 你用过cosmo存储吗?因为我提到代码示例对于 inMemory 存储工作正常
    • 是的,我确定我使用的是同一个对话,并且我确保检索到的对话 ID 在两种情况下都是相同的。
    • did you use the cosmo storage ? 是的,我正在使用 Cosmosdb。你可以找到截图是我在 Cosmosdb 数据资源管理器中看到的数据。
    • 我不知道为什么它以前对我不起作用,但现在它起作用了!谢谢。
    • @FeiHan 试图理解你的代码,以便我可以在我的机器人中实现它。使用 HttpStatusCode、BotConversationData、CancellationToken、BotStoreType、DialogModule 和 IBotDataStore 出现错误。您能否详细说明您是如何在项目中创建这些的?非常感谢!
    【解决方案2】:

    activity.GetStateClient() 已弃用:https://github.com/Microsoft/BotBuilder/blob/a6b9ec56393d6e5a4be74b324f722b5ca8840b4a/CSharp/Library/Microsoft.Bot.Connector.Shared/ActivityEx.cs#L329

    它只使用默认状态服务。如果您将 BotBuilder-Azure 用于状态,则不会使用 .GetStateClient() 检索您的 CosmosDb 实现。关于如何使用 DialogModule.BeginLifetimeScopedialog.Context 方法操作状态,请参考@Fei 的回答。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-03
      • 1970-01-01
      • 2014-12-03
      • 2018-09-27
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 2018-06-30
      相关资源
      最近更新 更多