How to store UserState and ConversationState in Azure Cosmos DB (BotFramework)?

*爱你&永不变心* 提交于 2019-12-11 10:09:48

问题


I'm doing a bot with de Microsoft Bot Framework version V4. The documentation is really awful, and I'm having problems with Cosmos DB (Azure) when I try to store de UserSate and the ConversationState.

I tried every result in Google but nothing has worked yet. Plus, there no much information about the framework really.

Bellow is the code of the file Startup.cs.

public void ConfigureServices(IServiceCollection services)
{
    services.AddBot<SeguritoBot>(options =>
   {
       var secretKey = Configuration.GetSection("botFileSecret")?.Value;
       var botFilePath = Configuration.GetSection("botFilePath")?.Value;

    // Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection.
    var botConfig = BotConfiguration.Load(botFilePath ?? @".\Segurito.bot", secretKey);
   services.AddSingleton(sp => botConfig ?? throw new InvalidOperationException($"The .bot config file could not be loaded. ({botConfig})"));

    // Retrieve current endpoint.
    var environment = _isProduction ? "production" : "development";
   var service = botConfig.Services.FirstOrDefault(s => s.Type == "endpoint" && s.Name == environment);
   if (!(service is EndpointService endpointService))
   {
       throw new InvalidOperationException($"The .bot file does not contain an endpoint with name '{environment}'.");
   }

   options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);

    // Creates a logger for the application to use.
    ILogger logger = _loggerFactory.CreateLogger<SeguritoBot>();

    // Catches any errors that occur during a conversation turn and logs them.
    options.OnTurnError = async (context, exception) =>
   {
       logger.LogError($"Exception caught : {exception}");
       await context.SendActivityAsync("Sorry, it looks like something went wrong.");
   };

   var optionsConversation = new CosmosDbStorageOptions()
   {
       CosmosDBEndpoint = new Uri("--secret--"),
       AuthKey = "--secret--",
       DatabaseId = "--secret--",
       CollectionId = "--secret--"
   };

   var optionsUser = new CosmosDbStorageOptions()
   {
       CosmosDBEndpoint = new Uri("--secret--"),
       AuthKey = "--secret--",
       DatabaseId = "--secret--",
       CollectionId = "--secret--"
   };

   IStorage dataStoreConversationState = new CosmosDbStorage(optionsConversation);
   IStorage dataStoreUserState = new CosmosDbStorage(optionsUser);

   options.Middleware.Add(new ConversationState<ConversationState>(dataStoreConversationState));
   options.Middleware.Add(new UserState<UserState>(dataStoreUserState));
   });
}

The last to lines are giving the error:

The non-generic type 'ConversationState' cannot be used with type arguments
The non-generic type 'ConversationState' cannot be used with type arguments 

回答1:


Ok, I'm not sure where you got this code from, but it looks like it's from a pre-release build. ConversationState and UserState are no longer middleware and no longer generic (e.g. don't have type arguments).

This is what a Startup::ConfigureServices should look like when using CosmosDB for state storage on a 4.x release build:

public class Startup
{
     public void ConfigureServices(IServiceCollection services)
     {
        // Only need a single storage instance unless you really are storing your conversation state and user state in two completely DB instances
        var storage = new CosmosDbStorage(new CosmosDbStorageOptions
        {
            // … set options here …
        });

        var conversationState = new ConversationState(storage);
        var userState = new UserState(storage);

        // Add the states as singletons
        services.AddSingleton(conversationState);
        services.AddSingleton(userState);

        // Create state properties accessors and register them as singletons
        services.AddSingleton(conversationState.CreateProperty<YourBotConversationState>("MyBotConversationState"));
        services.AddSingleton(userState.CreateProperty<YourBotUserState>("MyBotUserState"));

        services.AddBot<SeguritoBot>(options =>
        {
           // … set options here …
        });
     }
}

Now, in your bot, if you want to access those properties, you take them as dependencies via the constructor:

public class SeguritoBot : IBot
{
    private readonly ConversationState _conversationState;
    private readonly UserState _userState;
    private readonly IStatePropertyAccessor<YourBotConversationState> _conversationStatePropertyAccessor;
    private readonly IStatePropertyAccessor<YourBotUserState> _userStatePropertyAccessor;

    public SeguritoBot(
        ConversationState conversationState, 
        UserState userState,
        IStatePropertyAccessor<YourBotConversationState> conversationStatePropertyAccessor,
        IStatePropertyAccessor<YourBotUserState> userStatePropertyAccesssor)
    {
        _conversationState = conversationState;
        _userState = userState;
        _conversationStatePropertyAcessor = conversationStatePropertyAcessor;
        _userStatePropertyAcessor = userStatePropertyAcessor;
    }

    public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        var currentConversationState = await _conversationStatePropertyAccessor.GetAsync(
            turnContext,
            () => new YourBotConversationState(), 
            cancellationToken);

        // Access properties for this conversation
        // currentConversationState.SomeProperty

        // Update your conversation state property
        await _conversationStatePropertyAccessor.SetAsync(turnContext, currentConversationState, cancellationToken);

        // Commit any/all changes to conversation state properties
        await _conversationState.SaveChangesAsync(turnContext, cancellationToken);
    }
}

Obviously you can do the same with the user state property and you can support multiple properties per state scope with more calls to CreateProperty and injecting those IStatePropertyAccessor<T> as well, etc.



来源:https://stackoverflow.com/questions/54117431/how-to-store-userstate-and-conversationstate-in-azure-cosmos-db-botframework

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!