Как сохранить UserState и ConversationState в Azure Cosmos DB (BotFramework)? - PullRequest
0 голосов
/ 09 января 2019

Я занимаюсь ботом с версией de Microsoft Bot Framework V4. Документация действительно ужасная, и у меня возникают проблемы с Cosmos DB (Azure), когда я пытаюсь сохранить de UserSate и ConversationState.

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

Ниже приведен код файла 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 non-generic type 'ConversationState' cannot be used with type arguments
The non-generic type 'ConversationState' cannot be used with type arguments 

1 Ответ

0 голосов
/ 10 января 2019

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

Вот как должен выглядеть Startup::ConfigureServices при использовании CosmosDB для хранения состояний в сборке релиза 4.x:

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

Теперь, в вашем боте, если вы хотите получить доступ к этим свойствам, вы берете их как зависимости через конструктор:

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

Очевидно, что вы можете сделать то же самое со свойством состояния пользователя, и вы можете поддерживать несколько свойств для каждой области состояния с большим количеством вызовов CreateProperty, а также добавлением этих IStatePropertyAccessor<T> и т. Д.

...