c# - IIS 池回收后的对话参考(并发字典变为空白)
问题描述
我们在 Bot framework-4 中有一个使用 .Net c# sdk 的机器人设计。该机器人托管在 IIS 上,可在 Directline、MS Teams 等不同渠道上使用。我们希望向 MS 团队中的所有用户发送主动消息以通知他们,无论他们是否与机器人通信。主动消息将是 1:1 消息。
经过大量研发后,我们发现只有在存在对话参考时才能向用户发送主动消息。(让我知道是否还有其他方法。)
使用以下链接和示例向用户发送主动消息:
我们正在使用 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 中的代码相同。我们面临两个问题:
当 IIS 池被回收时,具有会话引用的并发字典变为空白,我们无法向用户发送主动消息,如何将其存储在 Blob 存储中并在通知控制器中访问?
我们想向所有用户发送主动消息,无论他们是否与机器人通信,有什么方法可以实现这一点?尝试了本文的第三种方法。但挑战在于,我们无法根据用户 ID 或用户主体名称向用户发送消息。
解决方案
我想为答案添加评论,但我没有足够的声誉这样做。只是为了阐述第 1 点,如果您想问我们在哪里可以获取并保存对话引用,您可以通过名为 OnConversationUpdateActivityAsync 的方法获取它。
我花了一些时间才做到这一点,所以我认为分享是有用的。您可以从活动中获取大量信息,例如用户 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;
...
...
...
}
}
推荐阅读
- linux - 无法发送传真“Err_Call_Rejected”
- git - 文件被删除时如何找到提交?
- datetime - 如何在 Flutter 中使用 Streams 更新时间?
- database - Laravel 我无法随心所欲地捕获数据
- graphql - Graphql 只允许一个根查询?
- python - 如何在 Python 中使用扩展运算符
- ios - rx.sentMessage(#selector(UIViewController.viewDidLoad)) 没有触发
- rxjs - 添加到先前合并的 Observable
- android - 如何修复“android.arch.lifecycle:runtime”在 Flutter 中的编译时和运行时版本不同?
- wpf - WPF 弹出控件正在立即关闭