Поделиться через


Непосредственная запись в хранилище

ОБЛАСТЬ ПРИМЕНЕНИЯ: ПАКЕТ SDK версии 4

Вы можете выполнять операции записи и чтения непосредственно в объекте хранилища, не используя ПО промежуточного слоя или объект контекста. Это может требоваться для данных, которые бот использует для сохранения беседы, или данных, которые поступают из источника за пределами потока общения бота. В рамках этой модели хранилища данные считываются непосредственно из хранилища без использования диспетчера состояний. В примерах кода в этой статье показано, как считывать и записывать данные в хранилище с помощью памяти, Cosmos DB, BLOB-объектов Azure и хранилища расшифровки BLOB-объектов Azure.

Примечание.

Пакеты SDK для JavaScript, C# и Python для Bot Framework по-прежнему будут поддерживаться, однако пакет SDK java отменяется с окончательной долгосрочной поддержкой, заканчивающейся в ноябре 2023 года.

Существующие боты, созданные с помощью пакета SDK для Java, будут продолжать функционировать.

Для создания нового бота рекомендуется использовать Microsoft Copilot Studio и ознакомиться с выбором подходящего решения copilot.

Дополнительные сведения см. в статье "Будущее создания бота".

Необходимые компоненты

Примечание.

Вы можете установить шаблоны из Visual Studio.

  1. В меню выберите "Расширения" и "Управление расширениями".
  2. В диалоговом окне "Управление расширениями" найдите и установите шаблоны SDK Bot Framework версии 4 для Visual Studio.

Сведения о развертывании ботов .NET в Azure см. в статье о подготовке и публикации бота.

Об этом примере

Пример кода в этой статье определяет структуру базового эхо-бота. Добавив дополнительный код (см. ниже), вы сможете расширить функции этого бота. Этот расширенный код создает список для сохранения входных данных пользователей по мере их получения. Каждый поворот, полный список входных данных пользователя, сохраненный в памяти, повторяется пользователю. Структура данных, содержащая этот список входных данных, затем изменяется для сохранения в хранилище. В этот пример кода добавляются различные типы хранилища.

Хранилище в памяти

Пакет SDK Bot Framework позволяет хранить вводимые пользователем данные с помощью размещенного в памяти хранилища. Так как хранилище в памяти очищается при каждом перезапуске бота, оно лучше всего подходит для тестирования и не предназначено для использования в рабочей среде. Постоянные хранилища, такие как хранилище базы данных, лучше всего подходят для ботов в рабочей среде.

Создание базового бота

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

Замените код в EchoBot.cs следующим кодом:

using System;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

// Represents a bot saves and echoes back user input.
public class EchoBot : ActivityHandler
{
   // Create local Memory Storage.
   private static readonly MemoryStorage _myStorage = new MemoryStorage();

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

   // Class for storing a log of utterances (text of messages) as a list.
   public class UtteranceLog : IStoreItem
   {
      // A list of things that users have said to the bot
      public List<string> UtteranceList { get; } = new List<string>();

      // The number of conversational turns that have occurred
      public int TurnNumber { get; set; } = 0;

      // Create concurrency control where this is used.
      public string ETag { get; set; } = "*";
   }

   // Echo back user input.
   protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
   {
      // preserve user input.
      var utterance = turnContext.Activity.Text;

      // Make empty local log-items list.
      UtteranceLog logItems = null;

      // See if there are previous messages saved in storage.
      try
      {
         string[] utteranceList = { "UtteranceLog" };
         logItems = _myStorage.ReadAsync<UtteranceLog>(utteranceList).Result?.FirstOrDefault().Value;
      }
      catch
      {
         // Inform the user an error occurred.
         await turnContext.SendActivityAsync("Sorry, something went wrong reading your stored messages!");
      }

      // If no stored messages were found, create and store a new entry.
      if (logItems is null)
      {
         // Add the current utterance to a new object.
         logItems = new UtteranceLog();
         logItems.UtteranceList.Add(utterance);

         // Set initial turn counter to 1.
         logItems.TurnNumber++;

         // Show user new user message.
         await turnContext.SendActivityAsync($"{logItems.TurnNumber}: The list is now: {string.Join(", ", logItems.UtteranceList)}");

         // Create dictionary object to hold received user messages.
         var changes = new Dictionary<string, object>();
         {
            changes.Add("UtteranceLog", logItems);
         }
         try
         {
            // Save the user message to your Storage.
            await _myStorage.WriteAsync(changes, cancellationToken);
         }
         catch
         {
            // Inform the user an error occurred.
            await turnContext.SendActivityAsync("Sorry, something went wrong storing your message!");
         }
      }
      // Else, our storage already contained saved user messages, add new one to the list.
      else
      {
         // add new message to list of messages to display.
         logItems.UtteranceList.Add(utterance);
         // increment turn counter.
         logItems.TurnNumber++;

         // show user new list of saved messages.
         await turnContext.SendActivityAsync($"{logItems.TurnNumber}: The list is now: {string.Join(", ", logItems.UtteranceList)}");

         // Create Dictionary object to hold new list of messages.
         var changes = new Dictionary<string, object>();
         {
            changes.Add("UtteranceLog", logItems);
         };

         try
         {
            // Save new list to your Storage.
            await _myStorage.WriteAsync(changes,cancellationToken);
         }
         catch
         {
            // Inform the user an error occurred.
            await turnContext.SendActivityAsync("Sorry, something went wrong storing your message!");
         }
      }
   }
}

Запуск бота

Запустите бот на локальном компьютере.

Запуск эмулятора и подключение к боту

Установите эмулятор Bot Framework Далее, запустите эмулятор и подключитесь к боту в эмуляторе:

  1. Выберите ссылку "Создать бота" на вкладке приветствия эмулятора.
  2. Заполните поля для подключения к боту, используя сведения на веб-странице, отображаемой при запуске бота.

Взаимодействие с ботом

Отправьте сообщение боту. Он отобразит список полученных сообщений.

Беседа с ботом, показывая боту список сообщений от пользователя.

Оставшаяся часть этой статьи демонстрирует сохранение в постоянном хранилище вместо внутренней памяти бота.

Использование Cosmos DB

Внимание

Класс хранилища Cosmos DB является устаревшим. Контейнеры, изначально созданные с помощью CosmosDbStorage, не имели набора ключей секций, и были предоставлены ключ секции по умолчанию _/partitionKey.

Контейнеры, созданные с помощью хранилища Cosmos DB, можно использовать с секционированным хранилищем Cosmos DB. См. сведения о секционировании в Azure Cosmos DB.

Кроме того, обратите внимание, что в отличие от устаревшего хранилища Cosmos DB секционированные хранилища Cosmos DB не создают базу данных в учетной записи Cosmos DB. Необходимо вручную создать новую базу данных, но пропустить создание контейнера вручную, так как CosmosDbPartitionedStorage создаст для вас контейнер.

Начав использовать хранилище в памяти, мы изменим код, чтобы начать работу с Azure Cosmos DB. Cosmos DB — это глобально распределенная многомодельная база данных Майкрософт. Azure Cosmos DB позволяет гибко и независимо масштабировать пропускную способность и ресурсы хранилища в любом количестве регионов Azure. Она гарантирует пропускную способность, задержку, доступность и согласованность в соответствии с комплексными Соглашениями об уровне обслуживания (SLA).

Настройка ресурса Cosmos DB

Чтобы использовать в боте Cosmos DB, необходимо создать ресурс базы данных, прежде чем приступать к написанию кода. Подробное описание создания базы данных и приложений Cosmos DB см. в кратком руководстве по .NET, Node.js или Python.

Создание учетной записи базы данных

  1. Создайте учетную запись для базы данных Azure Cosmos DB, перейдя на портал Azure. Найдите и выберите Azure Cosmos DB.

  2. На странице Azure Cosmos DB выберите "Создать", чтобы открыть страницу "Создать учетную запись Azure Cosmos DB".

    Снимок экрана: создание учетной записи Cosmos DB.

  3. Введите значения для следующих полей:

    1. Подписка. Выберите подписку Azure, которую нужно использовать для этой учетной записи Azure Cosmos.
    2. Группа ресурсов. Выберите существующую группу ресурсов или нажмите кнопку "Создать" и введите имя новой группы ресурсов.
    3. Имя учетной записи Введите имя для идентификации учетной записи Azure Cosmos. Так как элемент documents.azure.com добавляется к указанному вами имени для создания URI, используйте уникальное имя. Обратите внимание на следующие рекомендации.
      • Это имя должно быть уникальным в пределах Azure.
      • Имя должно иметь длину от 3 до 31 символов.
      • Имя может содержать только строчные буквы, цифры и символ дефиса (-).
    4. API. Выбор Core(SQL)
    5. Location. Выберите расположение, ближайшее к пользователям, чтобы предоставить им самый быстрый доступ к данным.
  4. Выберите Review + Create (Просмотреть и создать).

  5. После проверки нажмите кнопку "Создать".

Создание учетной записи занимает несколько минут. Подождите, пока на портале откроется страница с сообщением Поздравляем! Учетная запись Azure Cosmos DB создана.

Добавление базы данных

Примечание.

Не создавайте контейнер самостоятельно. Бот создаст его для вас при создании внутреннего клиента Cosmos DB, гарантируя правильность настройки состояния бота.

  1. Перейдите на страницу обозревателя данных в созданной учетной записи Cosmos DB, а затем выберите новую базу данных в раскрывающемся списке "Создать контейнер". Затем панель откроется справа от окна, где можно ввести сведения о новой базе данных.

    Снимок экрана: создание базы данных Cosmos DB.

  2. Введите идентификатор новой базы данных и, при необходимости, задайте пропускную способность (можно изменить ее позже) и нажмите кнопку "ОК ", чтобы создать базу данных. Запишите идентификатор базы данных, чтобы использовать его позже для настройки бота.

  3. Теперь, когда вы создали учетную запись Cosmos DB и базу данных, необходимо скопировать некоторые значения для интеграции новой базы данных в бот. Чтобы получить их, перейдите на вкладку Ключи в разделе параметров базы данных, которую вы создали в учетной записи Cosmos DB. На этой странице вам потребуется URI (конечная точка Cosmos DB) и первичный ключ (ключ авторизации).

Теперь у вас должна быть учетная запись Cosmos DB с базой данных и следующие значения, готовые к использованию в параметрах бота.

  • URI-адрес
  • Первичный ключ
  • Идентификатор базы данных

Добавление сведений о конфигурации Cosmos DB

Используйте сведения, которые вы записали в предыдущей части этой статьи, чтобы задать конечную точку, ключ авторизации и идентификатор базы данных. Наконец, выберите подходящее имя для контейнера, который будет создан в базе данных для хранения состояния бота. В приведенном ниже примере созданный контейнер Cosmos DB будет называться bot-storage.

Добавьте следующие сведения в файл конфигурации.

appsettings.json

"CosmosDbEndpoint": "<your-CosmosDb-URI>",
"CosmosDbAuthKey": "<your-primary-key>",
"CosmosDbDatabaseId": "<your-database-id>",
"CosmosDbContainerId": "bot-storage"

Установка пакетов Cosmos DB

Убедитесь, что у вас есть пакеты, необходимые для Cosmos DB.

Установите пакет NuGet Microsoft.Bot.Builder.Azure. Дополнительные сведения об использовании NuGet см. в статье "Установка пакетов и управление ими в Visual Studio с помощью диспетчер пакетов NuGet".

Реализация Cosmos DB

Примечание.

В версии 4.6 появился новый поставщик хранилища Cosmos DB — класс секционированного хранилища Cosmos DB класса. Исходный класс хранилища Cosmos DB является устаревшим. Контейнеры, созданные с помощью хранилища Cosmos DB, можно использовать с секционированным хранилищем Cosmos DB. См. сведения о секционировании в Azure Cosmos DB.

В отличие от устаревшего хранилища Cosmos DB, секционированного хранилища Cosmos DB не автоматически создает базу данных в учетной записи Cosmos DB. Необходимо вручную создать новую базу данных, но пропустить создание контейнера вручную, так как CosmosDbPartitionedStorage создаст для вас контейнер.

В следующем примере кода используется тот же код бота, что и пример хранилища памяти , приведенный выше, с исключениями, перечисленными здесь. В фрагментах кода ниже показана реализация хранилища Cosmos DB для myStorage, которая заменяет локальное хранилище памяти.

Сначала необходимо обновить Startup.cs для ссылки на библиотеку Azure построителя ботов:

using Microsoft.Bot.Builder.Azure;

Затем в методе ConfigureServices в Startup.cs создайте CosmosDbPartitionedStorage объект. Это будет передано в EchoBot конструктор с помощью внедрения зависимостей.

// Use partitioned CosmosDB for storage, instead of in-memory storage.
services.AddSingleton<IStorage>(
    new CosmosDbPartitionedStorage(
        new CosmosDbPartitionedStorageOptions
        {
            CosmosDbEndpoint = Configuration.GetValue<string>("CosmosDbEndpoint"),
            AuthKey = Configuration.GetValue<string>("CosmosDbAuthKey"),
            DatabaseId = Configuration.GetValue<string>("CosmosDbDatabaseId"),
            ContainerId = Configuration.GetValue<string>("CosmosDbContainerId"),
            CompatibilityMode = false,
        }));

В EchoBot.cs измените объявление private static readonly MemoryStorage _myStorage = new MemoryStorage(); переменной _myStorage следующим образом:

// variable used to save user input to CosmosDb Storage.
private readonly IStorage _myStorage;

Затем передайте объект конструктору IStorage EchoBot :

public EchoBot(IStorage storage)
{
    if (storage is null) throw new ArgumentNullException();
    _myStorage = storage;
}

Запуск бота Cosmos DB

Запустите бот на локальном компьютере.

Тестирование бота Cosmos DB с помощью эмулятора Bot Framework

Теперь запустите эмулятор Bot Framework и подключитесь к боту:

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

Взаимодействие с ботом Cosmos DB

Отправьте сообщение боту, и он отобразит список полученных сообщений.

Беседа с ботом, показывая боту список сообщений от пользователя.

Просмотр данных Cosmos DB

После запуска бота и сохранения сведений можно просмотреть данные, хранящиеся в портал Azure на вкладке Обозревателя данных.

Снимок экрана: обозреватель данных в портал Azure.

Использование хранилища BLOB-объектов

Хранилище BLOB-объектов Azure — это решение корпорации Майкрософт для хранения объектов в облаке. Хранилище BLOB-объектов оптимизировано для хранения огромных объемов неструктурированных данных, таких как текстовые или двоичные данные. В этом разделе объясняется, как создать учетную запись хранения BLOB-объектов Azure и контейнер, а затем как ссылаться на контейнер хранилища BLOB-объектов из бота.

Дополнительные сведения о хранилище BLOB-объектов см. в статье "Что такое хранилище BLOB-объектов Azure"?

Создание учетной записи хранилища BLOB-объектов

Для использования хранилища BLOB-объектов в боте необходимо выполнить некоторые настройки, прежде чем приступать к написанию кода.

  1. На портале Azure выберите Все службы.

  2. В разделе "Избранные" страницы "Все службы" выберите учетные записи хранения.

  3. На странице учетных записей хранения нажмите кнопку "Создать".

    Снимок экрана: создание учетной записи служба хранилища Azure.

  4. В поле Подписка выберите подписку, в которой будет создана учетная запись хранения.

  5. В поле Группа ресурсов выберите имеющуюся группу ресурсов или выберите Создать и введите имя новой группы ресурсов.

  6. В поле Имя учетной записи хранения введите имя учетной записи. Придерживайтесь приведенных ниже рекомендаций:

    • Это имя должно быть уникальным в пределах Azure.
    • Количество символов в имени должно быть от 3 до 24.
    • Имя может содержать только цифры и строчные буквы.
  7. В поле Расположение выберите расположение для учетной записи хранения или используйте расположение по умолчанию.

  8. Настройте остальные параметры установки:

  9. В разделе "Сведения о проекте" на странице "Создание учетной записи хранения" выберите нужные значения для подписки и группы ресурсов.

  10. В разделе сведений об экземпляре на странице "Создание учетной записи хранения" введите имя учетной записи хранения, а затем выберите значения расположения, типа учетной записи и репликации.

  11. Чтобы проверить параметры учетной записи хранения, выберите Проверить и создать.

  12. После проверки нажмите кнопку "Создать".

Создание контейнера хранилища BLOB-объектов

После создания учетной записи хранения BLOB-объектов откройте ее, а затем:

  1. Выберите Обозреватель службы хранилища (предварительная версия).

  2. Затем щелкните правой кнопкой мыши контейнеры BLOB-объектов

  3. Выберите " Создать контейнер BLOB-объектов" из раскрывающегося списка.

    Снимок экрана: создание контейнера BLOB-объектов.

  4. Введите имя в форме нового контейнера . Это имя будет использоваться для значения имени контейнера BLOB-объектов, чтобы предоставить доступ к учетной записи хранения BLOB-объектов. Придерживайтесь приведенных ниже рекомендаций:

    • Это имя может содержать только строчные буквы, цифры и дефисы.
    • Это имя должно начинаться с буквы или числа.
    • Перед каждым дефисом следует следовать допустимый символ, отличный от дефиса.
    • Имя должно иметь длину от 3 до 63 символов.

Добавление сведений о конфигурации хранилища BLOB-объектов

Найдите ключи хранилища BLOB-объектов, необходимые для настройки хранилища BLOB-объектов для бота, как показано выше:

  1. В портал Azure откройте учетную запись хранения BLOB-объектов и выберите ключи доступа в разделе "Параметры".
  2. Чтобы настроить бот для доступа к учетной записи хранения BLOB-объектов, используйте строку подключения в качестве значения для строка подключения BLOB-объекта.

Добавьте следующие сведения в файл конфигурации.

appsettings.json

"BlobConnectionString": "<your-blob-connection-string>",
"BlobContainerName": "<your-blob-container-name>",

Установка пакетов хранилища BLOB-объектов

Если ранее не установлено, установите следующие пакеты.

Установите пакет NuGet Microsoft.Bot.Builder.Azure.Blobs. Дополнительные сведения об использовании NuGet см. в статье "Установка пакетов и управление ими в Visual Studio с помощью диспетчер пакетов NuGet".

Реализация хранилища BLOB-объектов

Хранилище BLOB-объектов используется для хранения состояния бота.

Примечание.

По состоянию на версию 4.10 Microsoft.Bot.Builder.Azure.AzureBlobStorage не рекомендуется. Используйте новое Microsoft.Bot.Builder.Azure.Blobs.BlobsStorage в своем месте.

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

Приведенные ниже фрагменты кода показывают реализацию хранилища BLOB-объектов для myStorage, заменяющего локальное хранилище памяти.

Сначала необходимо обновить Startup.cs , чтобы ссылаться на библиотеку BLOB-объектов Azure построителя ботов:

Startup.cs

using Microsoft.Bot.Builder.Azure.Blobs;

Затем в методе ConfigureServices в Startup.cs создайте BlobsStorage объект, передавая значения из appsettings.json. Это будет передано в EchoBot конструктор с помощью внедрения зависимостей.

//Use Azure Blob storage, instead of in-memory storage.
services.AddSingleton<IStorage>(
    new BlobsStorage(
        Configuration.GetValue<string>("BlobConnectionString"),
        Configuration.GetValue<string>("BlobContainerName")
        ));

Теперь сначала необходимо обновить EchoBot.cs , чтобы ссылаться на библиотеку BLOB-объектов Azure построителя ботов:

EchoBot.cs

using Microsoft.Bot.Builder.Azure.Blobs;

Затем удалите или закомментируйте строку кода, которая создает переменную MemoryStorage "private static readonly MemoryStorage _myStorage = new MemoryStorage(); и создайте новую переменную, которая будет использоваться для сохранения входных данных пользователя в хранилище BLOB-объектов.

EchoBot.cs

// variable used to save user input to CosmosDb Storage.
private readonly IStorage _myStorage;

Затем передайте объект конструктору IStorage EchoBot :

public EchoBot(IStorage storage)
{
    if (storage is null) throw new ArgumentNullException();
    _myStorage = storage;
}

После указания учетной записи хранения BLOB-объектов код бота будет хранить и извлекать данные из хранилища BLOB-объектов.

После указания учетной записи хранения BLOB-объектов код бота будет хранить и извлекать данные из хранилища BLOB-объектов.

Запуск бота хранилища BLOB-объектов

Запустите бот на локальном компьютере.

Запустите эмулятор и подключите бот хранилища BLOB-объектов

Затем запустите эмулятор и подключитесь к боту в эмуляторе:

  1. Выберите ссылку "Создать бота" на вкладке "Приветствие" эмулятора.
  2. Заполните поля для подключения к боту, используя сведения на веб-странице, отображаемой при запуске бота.

Взаимодействие с ботом хранилища BLOB-объектов

Отправьте сообщение боту, и он отобразит список полученных сообщений.

Беседа с ботом, показывая боту список сообщений от пользователя.

Просмотр данных хранилища BLOB-объектов

После запуска бота и сохранения сведений его можно просмотреть на вкладке Обозреватель службы хранилища на портал Azure.

Хранилище расшифровок разговоров в BLOB-объектах

Хранилище расшифровок в BLOB-объектах Azure — это специализированное хранилище, которое позволяет легко сохранять и получать разговоры пользователей в виде записей расшифровок. Хранилище расшифровки BLOB-объектов Azure полезно для автоматического записи входных данных пользователей для проверки производительности бота.

Примечание.

В настоящее время Python не поддерживает хранилище расшифровок BLOB-объектов Azure. Хотя JavaScript поддерживает хранилище расшифровок BLOB-объектов, следующие указания предназначены только для C#.

Настройка контейнера хранилища расшифровки BLOB-объектов

Хранилище расшифровок разговоров в BLOB-объектах Azure использует ту же учетную запись хранилища BLOB-объектов, которая описана в разделах Создание учетной записи хранилища BLOB-объектов и Добавление сведений о конфигурации выше. Теперь добавьте контейнер для хранения расшифровок.

Снимок экрана: создание контейнера BLOB-объектов для использования в качестве хранилища транскрибирования.

  1. Откройте учетную запись хранилища BLOB-объектов Azure
  2. Выберите Обозреватель службы хранилища.
  3. Щелкните правой кнопкой мыши Контейнеры больших двоичных объектов и выберите Создать контейнер BLOB-объектов.
  4. Введите имя контейнера расшифровки и нажмите кнопку "ОК". (Мы ввели mybottranscripts)

Реализация хранилища расшифровки BLOB-объектов

В коде ниже указатель на хранилище расшифровок _myTranscripts подключается к новой учетной записи хранилища BLOB-объектов с расшифровками. Чтобы создать эту ссылку с новым именем контейнера, <your-blob-transcript-container-name>, он создает новый контейнер в хранилище BLOB-объектов для хранения файлов расшифровки.

Хранилище расшифровок BLOB-объектов предназначено для хранения расшифровок бота.

Примечание.

По состоянию на версию 4.10 Microsoft.Bot.Builder.Azure.AzureBlobTranscriptStore не рекомендуется. Используйте новое Microsoft.Bot.Builder.Azure.Blobs.BlobsTranscriptStore в своем месте.

echoBot.cs

using Microsoft.Bot.Builder.Azure.Blobs;

public class EchoBot : ActivityHandler
{
   ...

   private readonly BlobsTranscriptStore _myTranscripts = new BlobsTranscriptStore("<your-azure-storage-connection-string>", "<your-blob-transcript-container-name>");

   ...
}

Хранение бесед пользователей в расшифровках BLOB-объектов Azure

После того как контейнер BLOB-объектов доступен для хранения расшифровок, вы можете начать сохранять беседы пользователей с ботом. Эти диалоги можно позже использовать для отладки, чтобы проанализировать взаимодействие пользователей с ботом. Каждый диалог перезапуска эмулятора инициирует создание нового списка бесед расшифровки. Следующий код сохраняет диалог с пользователем в сохраненном файле с расшифровками.

  • Текущая расшифровка сохраняется с использованием LogActivityAsync.
  • Сохраненные расшифровки можно получить с использованием ListTranscriptsAsync. В этом примере кода идентификатор каждого сохраненного транскрибирования сохраняется в списке с именем storedTranscripts. Позже этот список используется для управления количеством расшифровок, хранимых в больших двоичных объектах.

echoBot.cs


protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    await _myTranscripts.LogActivityAsync(turnContext.Activity);

    List<string> storedTranscripts = new List<string>();
    PagedResult<Microsoft.Bot.Builder.TranscriptInfo> pagedResult = null;
    var pageSize = 0;
    do
    {
       pagedResult = await _myTranscripts.ListTranscriptsAsync("emulator", pagedResult?.ContinuationToken);
       pageSize = pagedResult.Items.Count();

       // transcript item contains ChannelId, Created, Id.
       // save the channelIds found by "ListTranscriptsAsync" to a local list.
       foreach (var item in pagedResult.Items)
       {
          storedTranscripts.Add(item.Id);
       }
    } while (pagedResult.ContinuationToken != null);

    ...
}

Управление расшифровками, хранимыми в больших двоичных объектах

Хотя хранимые расшифровки можно использовать как средство отладки, со временем их количество превышает возможности хранилища. Дополнительный код ниже использует DeleteTranscriptAsync для удаления из хранилища BLOB-объектов всех извлеченных элементов расшифровок, кроме последних трех.

echoBot.cs


protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    await _myTranscripts.LogActivityAsync(turnContext.Activity);

    List<string> storedTranscripts = new List<string>();
    PagedResult<Microsoft.Bot.Builder.TranscriptInfo> pagedResult = null;
    var pageSize = 0;
    do
    {
       pagedResult = await _myTranscripts.ListTranscriptsAsync("emulator", pagedResult?.ContinuationToken);
       pageSize = pagedResult.Items.Count();

       // transcript item contains ChannelId, Created, Id.
       // save the channelIds found by "ListTranscriptsAsync" to a local list.
       foreach (var item in pagedResult.Items)
       {
          storedTranscripts.Add(item.Id);
       }
    } while (pagedResult.ContinuationToken != null);

    // Manage the size of your transcript storage.
    for (int i = 0; i < pageSize; i++)
    {
       // Remove older stored transcripts, save just the last three.
       if (i < pageSize - 3)
       {
          string thisTranscriptId = storedTranscripts[i];
          try
          {
             await _myTranscripts.DeleteTranscriptAsync("emulator", thisTranscriptId);
           }
           catch (System.Exception ex)
           {
              await turnContext.SendActivityAsync("Debug Out: DeleteTranscriptAsync had a problem!");
              await turnContext.SendActivityAsync("exception: " + ex.Message);
           }
       }
    }
    ...
}

Дополнительные сведения о классе см. в статье "Хранилище расшифровок BLOB-объектов Azure".

Дополнительная информация

Управление параллелизмом с помощью тегов eTag

В примере кода бота мы задали свойству eTag каждого из них IStoreItem *значение . Член eTag (тег сущности) объекта хранилища используется в Cosmos DB для управления параллелизмом. eTag указывает базе данных, что делать, если другой экземпляр бота изменил объект в том же хранилище, в которое записывает данные ваш бот.

Приоритет последней записи — разрешить перезапись

Если указать звездочку (*) в качестве значения свойства eTag, это означает, то приоритет принадлежит последнему боту, который выполняет запись. При создании нового хранилища данных можно задать eTag свойство, чтобы * указать, что вы ранее не сохранили данные, которые вы записываете, или хотите, чтобы последний модуль записи перезаписал любое ранее сохраненное свойство. Если параллелизм не является проблемой для бота, присвойте eTag свойству * значение для любых данных, которые вы записываете, включает перезаписи.

Поддержание параллелизма и предотвращение перезаписи

Если нужно предотвратить параллельный доступ к свойству и избежать перезаписи данных другим экземпляром бота, при сохранении данных в Cosmos DB используйте другое значение свойства eTag, отличное от *. Бот получает ответ на ошибку с сообщением etag conflict key= при попытке сохранить данные о состоянии и eTag не совпадает со значением eTag в хранилище.

По умолчанию хранилище Cosmos DB проверяет равенство свойства eTag в объекте хранилища каждый раз, когда бот записывает данные в этот элемент, а затем включает в это свойство новое уникальное значение после каждой операции записи. Если значение свойства eTag во время записи не соответствует значению свойства eTag в хранилище, это означает, что другой бот или поток изменили данные.

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

Во-первых, создайте класс, который реализует IStoreItem.

EchoBot.cs

public class Note : IStoreItem
{
    public string Name { get; set; }
    public string Contents { get; set; }
    public string ETag { get; set; }
}

Затем создайте начальную заметку, создав объект хранилища и добавив объект в это хранилище.

EchoBot.cs

// create a note for the first time, with a non-null, non-* ETag.
var note = new Note { Name = "Shopping List", Contents = "eggs", ETag = "x" };

var changes = Dictionary<string, object>();
{
    changes.Add("Note", note);
};
await NoteStore.WriteAsync(changes, cancellationToken);

Впоследствии обновите заметку, сохранив значение eTag, прочитанное из хранилища.

EchoBot.cs

var note = NoteStore.ReadAsync<Note>("Note").Result?.FirstOrDefault().Value;

if (note != null)
{
    note.Contents += ", bread";
    var changes = new Dictionary<string, object>();
    {
         changes.Add("Note1", note);
    };
    await NoteStore.WriteAsync(changes, cancellationToken);
}

Если заметка в хранилище была изменена перед записью ваших изменений, то при вызове Write возникнет исключение.

Для поддержания параллелизма всегда считывайте значение свойства из хранилища, затем изменяйте прочитанное свойство, чтобы сохранить eTag. При считывании сведений о пользователях из хранилища ответ будет содержать свойство eTag. Если вы изменили данные и записываете обновленные данные в хранилище, ваш запрос должен включать свойство eTag, содержащее то же значение, которое было прочитано ранее. Однако при записи объекта со свойством eTag, имеющим значение *, будет разрешена перезапись любых других изменений.

Следующие шаги

Теперь, когда вы знаете, как читать и записывать непосредственно из хранилища, можно посмотреть, как можно использовать диспетчер состояний для этого.