IIS 池回收后的对话引用(并发字典变为空白)
conversation reference (concurrent dictionary become blank) after IIS pool recycle
我们使用 .Net c# sdk 在 Bot framework-4 中设计了一个机器人。该机器人托管在 IIS 上并且可用
在 Directline、MS Teams 等不同渠道上。我们希望向 MS 团队中的所有用户发送主动消息以通知他们,无论他们是否与 bot 通信。主动消息将是 1:1 条消息。
经过大量研发,我们发现只有在存在对话参考时,我们才能向用户发送主动消息。 (如果其他方式也可行,请告诉我。)
使用下面的 link 和示例向用户发送主动消息:
我们正在使用 cosmos DB 容器和自动保存中间件进行机器人对话状态和用户状态管理。
Startup.cs 文件的 ConfigureServices 方法中的代码:
var blobDbService = botConfig.Services.FirstOrDefault(s => s.Type == ServiceTypes.BlobStorage) ?? throw new Exception("Please configure your Blob service in your .bot file.");
var BlobDb = blobDbService as BlobStorageService;
var dataStore = new AzureBlobStorage(BlobDb.ConnectionString, BlobDb.Container);
var userState = new UserState(dataStore);
var conversationState = new ConversationState(dataStore);
services.AddSingleton(dataStore);
services.AddSingleton(userState);
services.AddSingleton(conversationState);
services.AddSingleton<ConcurrentDictionary<string, ConversationReference>>();
services.AddSingleton(new BotStateSet(userState, conversationState));
services.AddBot<EnterpriseTiBOT>(options =>
{
// Autosave State Middleware (saves bot state after each turn)
options.Middleware.Add(new AutoSaveStateMiddleware(userState, conversationState));
}
为每个用户存储对话参考的代码:
private void AddConversationReference(Activity activity)
{
var conversationReference = activity.GetConversationReference();
_conversationReferences.AddOrUpdate(conversationReference.User.Id, conversationReference, (key, newValue) => conversationReference);
}
protected override async Task OnStartAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
{
AddConversationReference(dc.Context, cancellationToken);
}
notifyContoller 中的代码与 GitHub Sample 中的代码相同。我们面临 2 个问题:
当IIS池被回收时,具有会话引用的并发字典变为空白,我们无法将主动消息发送给用户,如何将其存储在Blob存储中并在通知控制器?
我们想向所有用户发送主动消息,无论他们是否与 bot 进行过通信,有什么方法可以实现吗?尝试了 this 文章中的第三种方法。但挑战是,我们无法根据用户 ID 或用户主体名称向用户发送消息。
- 有多种方法可以存储对话和用户信息。您应该将这些详细信息存储在更持久的位置而不是内存中。这是一个 sample app code,它在安装应用程序时在 cosmos DB 中存储用户详细信息和对话 ID。您可以查看实施部分。它可以是任何存储(blob,SQL)。
- 要发送主动消息,用户必须有权访问您的应用。您可以为来自 Teams admin portal. Here is a reference documentation 的租户中的每个人安装您的应用程序,以便从管理门户管理应用程序。
您需要有对话 ID(在机器人和用户之间)才能发送主动消息。对话 ID 是在为用户安装机器人时创建的,或者在用户所属的 team/group 中创建。
我想对答案添加评论,但我没有足够的声誉来这样做。只是为了说明第 1 点,如果您想问我们在哪里可以获取和保存对话引用,您可以通过名为:OnConversationUpdateActivityAsync.
的方法获取它
我花了一些时间才弄到这个,所以我认为分享它很有用。
您可以从 activity 中获得很多信息,例如用户 ID、频道 ID,这里是一些示例代码:
public class ProactiveBot : ActivityHandler
{
...
...
protected override Task OnConversationUpdateActivityAsync(ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var conversationReferences = turnContext.Activity.GetConversationReference();
//this is your user's ID
string userId = conversationReference.User.Id;
//this is the bot's ID and will be the same for all activities under same bot.
string botId = conversationReference.Bot.Id;
...
...
...
}
}
我们使用 .Net c# sdk 在 Bot framework-4 中设计了一个机器人。该机器人托管在 IIS 上并且可用 在 Directline、MS Teams 等不同渠道上。我们希望向 MS 团队中的所有用户发送主动消息以通知他们,无论他们是否与 bot 通信。主动消息将是 1:1 条消息。
经过大量研发,我们发现只有在存在对话参考时,我们才能向用户发送主动消息。 (如果其他方式也可行,请告诉我。)
使用下面的 link 和示例向用户发送主动消息:
我们正在使用 cosmos DB 容器和自动保存中间件进行机器人对话状态和用户状态管理。
Startup.cs 文件的 ConfigureServices 方法中的代码:
var blobDbService = botConfig.Services.FirstOrDefault(s => s.Type == ServiceTypes.BlobStorage) ?? throw new Exception("Please configure your Blob service in your .bot file.");
var BlobDb = blobDbService as BlobStorageService;
var dataStore = new AzureBlobStorage(BlobDb.ConnectionString, BlobDb.Container);
var userState = new UserState(dataStore);
var conversationState = new ConversationState(dataStore);
services.AddSingleton(dataStore);
services.AddSingleton(userState);
services.AddSingleton(conversationState);
services.AddSingleton<ConcurrentDictionary<string, ConversationReference>>();
services.AddSingleton(new BotStateSet(userState, conversationState));
services.AddBot<EnterpriseTiBOT>(options =>
{
// Autosave State Middleware (saves bot state after each turn)
options.Middleware.Add(new AutoSaveStateMiddleware(userState, conversationState));
}
为每个用户存储对话参考的代码:
private void AddConversationReference(Activity activity)
{
var conversationReference = activity.GetConversationReference();
_conversationReferences.AddOrUpdate(conversationReference.User.Id, conversationReference, (key, newValue) => conversationReference);
}
protected override async Task OnStartAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
{
AddConversationReference(dc.Context, cancellationToken);
}
notifyContoller 中的代码与 GitHub Sample 中的代码相同。我们面临 2 个问题:
当IIS池被回收时,具有会话引用的并发字典变为空白,我们无法将主动消息发送给用户,如何将其存储在Blob存储中并在通知控制器?
我们想向所有用户发送主动消息,无论他们是否与 bot 进行过通信,有什么方法可以实现吗?尝试了 this 文章中的第三种方法。但挑战是,我们无法根据用户 ID 或用户主体名称向用户发送消息。
- 有多种方法可以存储对话和用户信息。您应该将这些详细信息存储在更持久的位置而不是内存中。这是一个 sample app code,它在安装应用程序时在 cosmos DB 中存储用户详细信息和对话 ID。您可以查看实施部分。它可以是任何存储(blob,SQL)。
- 要发送主动消息,用户必须有权访问您的应用。您可以为来自 Teams admin portal. Here is a reference documentation 的租户中的每个人安装您的应用程序,以便从管理门户管理应用程序。
您需要有对话 ID(在机器人和用户之间)才能发送主动消息。对话 ID 是在为用户安装机器人时创建的,或者在用户所属的 team/group 中创建。
我想对答案添加评论,但我没有足够的声誉来这样做。只是为了说明第 1 点,如果您想问我们在哪里可以获取和保存对话引用,您可以通过名为:OnConversationUpdateActivityAsync.
的方法获取它我花了一些时间才弄到这个,所以我认为分享它很有用。 您可以从 activity 中获得很多信息,例如用户 ID、频道 ID,这里是一些示例代码:
public class ProactiveBot : ActivityHandler
{
...
...
protected override Task OnConversationUpdateActivityAsync(ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var conversationReferences = turnContext.Activity.GetConversationReference();
//this is your user's ID
string userId = conversationReference.User.Id;
//this is the bot's ID and will be the same for all activities under same bot.
string botId = conversationReference.Bot.Id;
...
...
...
}
}