c# - 如何在 Azure Cosmos DB (BotFramework) 中存储 UserState 和 ConversationState?

标签 c# asp.net-core botframework azure-cosmosdb state-management

我正在使用 Microsoft Bot Framework V4 版本制作一个机器人。该文档真的很糟糕,当我尝试存储 de UserSate 和 ConversationState 时,我在使用 Cosmos DB (Azure) 时遇到了问题。

我尝试了 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 

最佳答案

好吧,我不确定您从哪里获得此代码,但它看起来像是来自预发布版本。 ConversationStateUserState不再是中间件,也不再通用(例如没有类型参数)。

这就是Startup::ConfigureServices在 4.x 版本构建上使用 CosmosDB 进行状态存储时应该类似于:

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 支持每个状态范围的多个属性。并注入(inject)那些IStatePropertyAccessor<T>还有等等

关于c# - 如何在 Azure Cosmos DB (BotFramework) 中存储 UserState 和 ConversationState?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54117431/

相关文章:

c# - 使用服务器端动态创建的 TableRow 的 "onclick"

linux - 在 Ubuntu 上运行独立的 ASP.NET Core 应用程序

asp.net - ASP.NET Core 中的 OAuth 授权服务

azure - LUIS 从免费订阅到付费订阅

c# - 表单流枚举提示错误

c# - Dapper - 将列数未知的结果集映射到具有数组属性的对象

c# - 克隆方法与直接将实例分配给另一个方法有什么区别

c# - WPF FrameworkElement 父级和移动 UIElement

c# - 我可以使用 JWT 进行身份验证,但我的名称声明在 ASP.NET Core 应用程序中无法识别

node.js - 当机器人识别器向 Luis 模型发出异步请求时,如何使用 botframework 的 sendTyping()?