简体   繁体   中英

Cosmos, retrieving conversation data within MessageController

I'm trying to replace the InMemory storage with Cosmos storage provided by Azure.

I'm storing some information within the conversation data, using it within my dialogs and resetting it from my message controller if a certain command was sent.

The way I access my conversation data within a dialog is :

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

The way I'm resetting my data from within the messageContoller is :

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);

The previous line of codes are working properly if I used InMemory. as soon as I switch to cosmos the resetting part of code fails. While debugging the issue I found that the conversation data object returned is never the same as the one returned from within the dialog and I was unable to reset the variables.

This is the way I'm connecting to cosmos database:

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();

});

Any idea why this is happening ?

Edit:

When using the im memory storage this code works just fine, but replacing the storage with the cosmos storage fails to retrieve the conversation data outside the dialog (the dialog gets/sets the conversation data correctly but the StateClents fails to retrieve the data correctly it returns an empty object but the weird part is that is has the same conversation ID as the one returned from the dialog)

While debugging the issue I found that the conversation data object returned is never the same as the one returned from within the dialog and I was unable to reset the variables.

Please make sure you are using same conversation when you do saving data and resetting data operations.

Besides, I do a test using the following sample code, I can save and reset conversation data as expected.

In message controller:

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; }
}

In dialog:

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);
}

Test steps:

在此输入图像描述

After enter hello bot , can find it saved as conversation data in Cosmosdb.

在此输入图像描述

After enter “reset”, can find the value of varName is reset to null .

在此输入图像描述

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

It only uses the default state service. If you are using BotBuilder-Azure for state, then your CosmosDb implementation will not be retrieved using .GetStateClient(). Please refer to @Fei's answer for how to manipulate state using DialogModule.BeginLifetimeScope or dialog.Context methods.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM