Как использовать State Accessors для получения свойств в Bot Framework - PullRequest
0 голосов
/ 11 октября 2019

Одной из функций моего бота является обработка корзины покупок. Пользователь может добавлять элементы в любом месте разговора, а затем заканчивать покупки, чтобы закрыть корзину товаров.

Чтобы не передавать корзину из диалога в диалог, я хотел бы создать свойство UserProfile в UserState (Свойство UserProfile имеет атрибут ShoppingCart), но я не совсем знаю, как правильно его использовать.

Мой главный диалог содержит набор дочерних диалогов, и некоторые из них должны иметь возможность доступаShoppingCart объект. Я нашел несколько примеров в примерах, но ни один из них не дает того, чего я хочу достичь. В примере State Management:

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            // Get the state properties from the turn context.

            var conversationStateAccessors =  _conversationState.CreateProperty<ConversationData>(nameof(ConversationData));
            var conversationData = await conversationStateAccessors.GetAsync(turnContext, () => new ConversationData());

            var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
            var userProfile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile());

            if (string.IsNullOrEmpty(userProfile.Name))
            {
                // First time around this is set to false, so we will prompt user for name.
                if (conversationData.PromptedUserForName)
                {   
                    // Set the name to what the user provided.
                    userProfile.Name = turnContext.Activity.Text?.Trim();

                    // Acknowledge that we got their name.
                    await turnContext.SendActivityAsync($"Thanks {userProfile.Name}. To see conversation data, type anything.");

                    // Reset the flag to allow the bot to go though the cycle again.
                    conversationData.PromptedUserForName = false;
                }
                else
                {
                    // Prompt the user for their name.
                    await turnContext.SendActivityAsync($"What is your name?");

                    // Set the flag to true, so we don't prompt in the next turn.
                    conversationData.PromptedUserForName = true;
                }
            }

Если я правильно понимаю, каждый раз, когда он хочет получить метод доступа, создается новое свойство? Или как только свойство будет создано, если вы вызовете CreateProperty, никакое свойство не будет создателем, и средство доступа будет возвращено?

Я думал о том, чтобы получить средство доступа на боте, а затем передать его в MainDialog, а затем вChildDialogs но это, в некотором роде, противоречит цели не пропускать ShoppingCart через диалоги.

Разве я не могу получить средства доступа без необходимости каждый раз создавать свойство?

У меня естьпрочитайте эту проблему , которая дает решение моей проблемы, но затем я увидел комментарий @ johnataylor , говорящий

Шаблон, который мы используем, заключается в том, чтобы отложитьсоздание средства доступа до тех пор, пока оно нам не понадобится - это, кажется, наиболее эффективно скрывает собственный шум.

Когда мне следует создавать средства доступа, если я хочу получить ShoppingCart (который находится внутри UserProfile свойство, к которому мне нужно получить доступ) в моих диалогах?

1 Ответ

1 голос
/ 11 октября 2019

Быстрый ответ: Вы должны создать аксессор во всех диалоговых окнах, где вам нужно манипулировать состоянием.

Подробный ответ:

CreateProperty физически не создает свойство, оно просто:

Создает определение свойства и регистрирует его в этом BotState

CreateProperty () вернет вам BotStatePropertyAccessor , из которого вы можете вызвать GetAsync , SetAsync и DeleteAsync они будут получать, устанавливать и удалять свойство из кэша состояний в контексте очереди. (Внутреннее состояние кэшированного бота)

Когда вы вызываете BotState.SaveChangesAsync () , это будет:

Если он изменился, записывает в хранилище объект состояния, который кэшируется в текущем объекте контекста для этого хода.

Каждый вызов GetAsync , SetAsync фактически вызовет BotState.LoadAsync () первымto:

Считывает объект текущего состояния и кэширует его в объекте контекста для этого хода.

И когда вызывается GetAsync () и ключ не найден , он автоматически вызовет SetAsync для установки этого нового свойства

Если вы используете AutoSaveStateMiddleware , это промежуточное ПО будет:

автоматически вызывает .SaveChanges () в конце хода для всех классов BotState, которыми он управляет.

...