Guardado de los datos del usuario y la conversaciónSave user and conversation data

se aplica a: SDK V4APPLIES TO: SDK v4

Inherentemente, un bot no tiene estado.A bot is inherently stateless. Una vez implementado el bot, no se puede ejecutar en el mismo proceso o en el mismo equipo de turno a otro.Once your bot is deployed, it may not run in the same process or on the same machine from one turn to the next. Sin embargo, el bot debe poder hacer un seguimiento del contexto de una conversación, para que pueda controlar su comportamiento y recordar las respuestas a las preguntas anteriores.However, your bot may need to track the context of a conversation so that it can manage its behavior and remember answers to previous questions. Las características de almacenamiento y estado de Bot Framework SDK permiten agregar un estado al bot.The state and storage features of the Bot Framework SDK allow you to add state to your bot. Los bots usan objetos de almacenamiento y administración de estado para administrar y conservar el estado.Bots use state management and storage objects to manage and persist state. El administrador de estados proporciona una capa de abstracción que permite acceder a las propiedades de estado mediante descriptores de acceso de las propiedades, independientemente del tipo de almacenamiento subyacente.The state manager provides an abstraction layer that lets you access state properties using property accessors, independent of the type of underlying storage.

PrerrequisitosPrerequisites

Acerca de este ejemploAbout this sample

Al recibir la entrada del usuario, este ejemplo comprueba el estado de la conversación almacenada para ver si se le ha pedido a este usuario que proporcione su nombre anteriormente.Upon receiving user input, this sample checks the stored conversation state to see if this user has previously been prompted to provide their name. Si no es así, se solicita el nombre del usuario y se almacena esa entrada en el estado del usuario.If not, the user's name is requested and that input is stored within user state. Si ya se le ha pedido, se usará el nombre almacenado en el estado del usuario para conversar con este y se devolverán sus datos de entrada junto con la hora de recepción y el identificador del canal de entrada, al usuario.If so, the name stored within user state is used to converse with the user and their input data, along with the time received and input channel Id, is returned back to the user. Los valores de hora y de identificador del canal se recuperan de los datos de conversación del usuario y se guardan en el estado de conversación.The time and channel Id values are retrieved from the user conversation data and then saved to conversation state. El siguiente diagrama muestra la relación entre el bot, el perfil de usuario y las clases de datos de conversación.The following diagram shows the relationship between the bot, user profile, and conversation data classes.

Definir las clasesDefine classes

El primer paso para configurar la administración de estados es definir las clases que contendrán la información que queremos administrar del usuario y el estado de la conversación.The first step in setting up state management is to define the classes containing the information to manage in the user and conversation state. En el ejemplo que se usa en este artículo se definen las clases siguientes:The example used in this article, defines the following classes:

  • En UserProfile.cs, defina una clase para la información UserProfile de usuario que el bot recopilará.In UserProfile.cs, you define a UserProfile class for the user information that the bot will collect.
  • En ConversationData.cs, se define una clase para controlar el estado de la conversación ConversationData mientras se recopila información del usuario.In ConversationData.cs, you define a ConversationData class to control our conversation state while gathering user information.

En los ejemplos de código siguientes se muestran las definiciones de las clases UserProfile y ConversationData.The following code examples show the definitions for the UserProfile and ConversationData classes.

UserProfile.csUserProfile.cs

// Defines a state property used to track information about the user.
public class UserProfile
{
    public string Name { get; set; }
}

ConversationData.csConversationData.cs

// Defines a state property used to track conversation data.
public class ConversationData
{
    // The time-stamp of the most recent incoming message.
    public string Timestamp { get; set; }

    // The ID of the user's channel.
    public string ChannelId { get; set; }

    // Track whether we have already asked the user's name
    public bool PromptedUserForName { get; set; } = false;
}

Creación de objetos de estado de conversación y usuarioCreate conversation and user state objects

A continuación, registre MemoryStorage que se usa para crear objetos y UserState ConversationState .Next, you register MemoryStorage that is used to create UserState and ConversationState objects. Los objetos de estado de usuario y conversación se crean en Startup y se inserta la dependencia en el constructor del bot.The user and conversation state objects are created at Startup and dependency injected into the bot constructor. Otros servicios que se registran para un bot son: un proveedor de credenciales, un adaptador y la implementación del bot.Other services for a bot that are registered are: a credential provider, an adapter, and the bot implementation.

Startup.csStartup.cs

// Create the storage we'll be using for User and Conversation state.
// (Memory is great for testing purposes - examples of implementing storage with
// Azure Blob Storage or Cosmos DB are below).
var storage = new MemoryStorage();
// Create the User state passing in the storage layer.
var userState = new UserState(storage);
services.AddSingleton(userState);

// Create the Conversation state passing in the storage layer.
var conversationState = new ConversationState(storage);
services.AddSingleton(conversationState);

Bots/StateManagementBot.csBots/StateManagementBot.cs

private BotState _conversationState;
private BotState _userState;

public StateManagementBot(ConversationState conversationState, UserState userState)
{
    _conversationState = conversationState;
    _userState = userState;
}

Incorporación de descriptores de acceso de propiedad de estadoAdd state property accessors

Ahora puede crear los accessors de propiedad mediante CreateProperty el método que proporciona un identificador para el objeto BotState .Now you create property accessors using the CreateProperty method that provides a handle to the BotState object. Cada descriptor de acceso a una propiedad de estado permite obtener o establecer el valor de la propiedad de estado correspondiente.Each state property accessor allows you to get or set the value of the associated state property. Antes de usar las propiedades de estado, use cada accessor para cargar la propiedad desde el almacenamiento y obtenerla de la caché de estado.Before you use the state properties, use each accessor to load the property from storage and get it from the state cache. Para obtener la clave con ámbito correcta asociada a la propiedad state, llame al GetAsync método .To get the properly scoped key associated with the state property, you call the GetAsync method.

Bots/StateManagementBot.csBots/StateManagementBot.cs

var conversationStateAccessors =  _conversationState.CreateProperty<ConversationData>(nameof(ConversationData));
var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));

Estado de acceso desde el botAccess state from your bot

En las secciones anteriores se describen los pasos en tiempo de inicialización para agregar a nuestro bot los descriptores de acceso de las propiedades de estado.The preceding section covers the initialization-time steps to add state property accessors to our bot. Ahora, puede usar esos accessors en tiempo de ejecución para leer y escribir información de estado.Now, you can use those accessors at run-time to read and write state information. El siguiente ejemplo de código usa este flujo de lógica:The sample code below uses the following logic flow:

  • Si userProfile.Name está vacío y conversationData.PromptedUserForName es true, se recupera el nombre de usuario proporcionado y se almacena en el estado de usuario.If userProfile.Name is empty and conversationData.PromptedUserForName is true, you retrieve the user name provided and store this within user state.
  • Si userProfile.Name está vacío y conversationData.PromptedUserForName es false, se pide el nombre del usuario.If userProfile.Name is empty and conversationData.PromptedUserForName is false, you ask for the user's name.
  • Si userProfile.Name almacenado anteriormente, recuperará la hora del mensaje y el identificador del canal de la entrada del usuario, volverá a enviar todos los datos al usuario y almacenará los datos recuperados en el estado de la conversación.If userProfile.Name was previously stored, you retrieve message time and channel Id from the user input, echo all data back to the user, and store the retrieved data within conversation state.

Bots/StateManagementBot.csBots/StateManagementBot.cs

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 through 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;
        }
    }
    else
    {
        // Add message details to the conversation data.
        // Convert saved Timestamp to local DateTimeOffset, then to string for display.
        var messageTimeOffset = (DateTimeOffset) turnContext.Activity.Timestamp;
        var localMessageTime = messageTimeOffset.ToLocalTime();
        conversationData.Timestamp = localMessageTime.ToString();
        conversationData.ChannelId = turnContext.Activity.ChannelId.ToString();

        // Display state data.
        await turnContext.SendActivityAsync($"{userProfile.Name} sent: {turnContext.Activity.Text}");
        await turnContext.SendActivityAsync($"Message received at: {conversationData.Timestamp}");
        await turnContext.SendActivityAsync($"Message received from: {conversationData.ChannelId}");
    }
}

Antes de salir del controlador de turnos, use el método SaveChangesAsync() de los objetos de administración de estado para volver a escribir todos los cambios de estado en el almacenamiento.Before you exit the turn handler, you use the state management objects' SaveChangesAsync() method to write all state changes back to storage.

Bots/StateManagementBot.csBots/StateManagementBot.cs

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

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

Probar el botTest the bot

Descargue e instale la versión más reciente de Bot Framework Emulator.Download and install the latest Bot Framework Emulator

  1. Ejecute el ejemplo localmente en la máquina.Run the sample locally on your machine. Si necesita instrucciones, consulte el archivo Léame en el ejemplo de C# o JS.If you need instructions, refer to the README file for C# Sample or JS Sample.
  2. Use el emulador para probar el bot tal y como se muestra a continuación.Use the Emulator to test the bot as shown below.

prueba del bot de estado de ejemplo

Recursos adicionalesAdditional resources

Privacidad: Si tiene intención de almacenar datos personales del usuario, debe garantizar el cumplimiento del Reglamento general de protección de datos.Privacy: If you intend to store user's personal data, you should ensure compliance with General Data Protection Regulation.

Administración de estados: Todas las llamadas de administración de estado son asincrónicas y prevalece el último en escribir de forma predeterminada.State management: All of the state management calls are asynchronous, and last-writer-wins by default. En la práctica, debe obtener, establecer y guardar el estado lo más próximos en el bot como sea posible.In practice, you should get, set, and save state as close together in your bot as possible.

Datos empresariales críticos: Utilice el estado del bot para almacenar las preferencias, el nombre de usuario o lo último que haya solicitado, pero no lo utilice para almacenar datos empresariales críticos.Critical business data: Use bot state to store preferences, user name, or the last thing they ordered, but do not use it to store critical business data. Para los datos críticos, cree sus propios componentes de almacenamiento o escríbalos directamente en el almacenamiento.For critical data, create your own storage components or write directly to storage.

Recognizer-Text: El ejemplo usa las bibliotecas Microsoft/Recognizers-Text para analizar y validar la entrada del usuario.Recognizer-Text: The sample uses the Microsoft/Recognizers-Text libraries to parse and validate user input. Para más información, consulte la página Información general.For more information, see the overview page.

Pasos siguientesNext steps

Ahora que sabe cómo configurar el estado para ayudarle a leer y escribir los datos del bot en el almacenamiento, vamos a aprender cómo realizar al usuario una serie de preguntas, validar sus respuestas y guardar su entrada.Now that you know how to configure state to help you read and write bot data to storage, let's learn how ask the user a series of questions, validate their answers, and save their input.