如何在 Azure Cosmos DB (BotFramework) 中存储 UserState 和 ConversationState?
How to store UserState and ConversationState in Azure Cosmos DB (BotFramework)?
我正在使用 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
好的,我不确定你从哪里得到这段代码,但它看起来像是来自预发布版本。 ConversationState
和 UserState
不再是中间件,也不再是通用的(例如,没有类型参数)。
这是 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
并注入那些 IStatePropertyAccessor<T>
等等.
我正在使用 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
好的,我不确定你从哪里得到这段代码,但它看起来像是来自预发布版本。 ConversationState
和 UserState
不再是中间件,也不再是通用的(例如,没有类型参数)。
这是 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
并注入那些 IStatePropertyAccessor<T>
等等.