首页 > 解决方案 > 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 中的代码相同。我们面临两个问题:

  1. 当 IIS 池被回收时,具有会话引用的并发字典变为空白,我们无法向用户发送主动消息,如何将其存储在 Blob 存储中并在通知控制器中访问?

  2. 我们想向所有用户发送主动消息,无论他们是否与机器人通信,有什么方法可以实现这一点?尝试了本文的第三种方法。但挑战在于,我们无法根据用户 ID 或用户主体名称向用户发送消息。

标签: c#iisbotframeworkmicrosoft-teamsazure-blob-storage

解决方案


我想为答案添加评论,但我没有足够的声誉这样做。只是为了阐述第 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;
        ...
        ...
        ...
    }
     
} 

推荐阅读