使用ITranscriptLogger与TranscriptMiddleware在Cosmos DB存聊天记录遇阻求助
解决使用ITranscriptLogger和TranscriptMiddleware将聊天历史存储到Cosmos DB的问题
我帮你梳理了代码里的几个关键问题,并且给出了修正后的实现方案,应该能解决聊天记录无法存储、容器不生成的问题:
关键问题分析
- 文档ID格式不合法:
activity.Id可能包含Cosmos DB禁止的字符(比如/、\、?),直接用作文档ID会导致存储失败 - 容器自动创建未启用:默认配置下CosmosDbStorage不会自动创建容器,需要显式开启
- 中间件添加方式有误:之前的代码在
AddBot中添加中间件,可能没有正确注入到Adapter的处理管道 - 异常未捕获:没有错误日志,很难排查存储失败的具体原因
修正后的完整代码
CosmosTranscriptStore.cs
using Microsoft.Bot.Builder; using Microsoft.Bot.Builder.Azure; using Microsoft.Bot.Schema; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; public class CosmosTranscriptStore : ITranscriptLogger { private readonly CosmosDbStorage _storage; public CosmosTranscriptStore(CosmosDbStorageOptions config) { // 开启自动创建容器(如果不存在) config.CreateIfNotExists = true; // 设置分区键,优化查询性能 config.PartitionKeyPath = "/ConversationId"; _storage = new CosmosDbStorage(config); } public async Task LogActivityAsync(IActivity activity) { if (activity == null) { throw new ArgumentNullException(nameof(activity)); } // 仅处理消息类型的活动(如需记录其他活动可移除此判断) var messageActivity = activity.AsMessageActivity(); if (messageActivity == null) { return; } // 生成符合Cosmos DB要求的文档ID:替换非法字符 var safeDocumentId = activity.Id.Replace("/", "_") .Replace("\\", "_") .Replace("?", "_"); // 构造强类型的聊天记录实体 var transcriptEntry = new TranscriptEntry { Id = safeDocumentId, ConversationId = activity.Conversation.Id, FromId = activity.From.Id, FromName = activity.From.Name, ToId = activity.Recipient.Id, ToName = activity.Recipient.Name, Text = messageActivity.Text, Timestamp = activity.Timestamp ?? DateTime.UtcNow, ChannelId = activity.ChannelId }; var documents = new Dictionary<string, object> { { safeDocumentId, transcriptEntry } }; try { await _storage.WriteAsync(documents, CancellationToken.None); } catch (Exception ex) { // 记录异常日志(可替换为你的日志框架) Console.WriteLine($"存储聊天记录失败: {ex.Message}"); throw; // 如需静默处理可移除throw } } // 强类型实体,便于后续查询和维护 public class TranscriptEntry { public string Id { get; set; } public string ConversationId { get; set; } public string FromId { get; set; } public string FromName { get; set; } public string ToId { get; set; } public string ToName { get; set; } public string Text { get; set; } public DateTime Timestamp { get; set; } public string ChannelId { get; set; } } }
Startup.cs
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Bot.Builder; using Microsoft.Bot.Builder.Azure; using Microsoft.Bot.Builder.Integration.AspNet.Core; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; public class Startup { private const string CosmosServiceEndpoint = "MyCosmosServiceEndpoint"; private const string CosmosDBKey = "MyCosmosDBKey"; private const string CosmosDBDatabaseName = "MyCosmosDBDatabaseName"; private const string CosmosDBCollectionName = "Transcript-storage"; public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); // 配置Cosmos DB存储选项 var cosmosOptions = new CosmosDbStorageOptions { AuthKey = CosmosDBKey, CollectionId = CosmosDBCollectionName, CosmosDBEndpoint = new Uri(CosmosServiceEndpoint), DatabaseId = CosmosDBDatabaseName, CreateIfNotExists = true }; // 注册自定义转录日志存储 services.AddSingleton<ITranscriptLogger>(new CosmosTranscriptStore(cosmosOptions)); // 配置Bot Adapter并注入转录中间件 services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>(sp => { var adapter = new AdapterWithErrorHandler(sp.GetService<IConfiguration>()); var transcriptLogger = sp.GetService<ITranscriptLogger>(); // 将转录中间件添加到Adapter管道 adapter.Use(new TranscriptLoggerMiddleware(transcriptLogger)); return adapter; }); // 注册Bot相关服务 services.AddSingleton<MainDialog>(); services.AddTransient<IBot, WelcomeBot<MainDialog>>(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); } app.UseDefaultFiles(); app.UseStaticFiles(); app.UseMvc(); } }
验证步骤
- 确保你使用的是Cosmos DB账户的Primary Key(不是资源令牌),并且Cosmos DB的网络访问设置允许你的Bot服务IP访问
- 运行Bot并发送几条测试消息,等待1-2分钟(Cosmos DB写入有轻微延迟)
- 登录Azure Portal,进入你的Cosmos DB账户,查看指定的数据库和容器,应该能看到存储的聊天记录文档
- 如果仍然没有数据,检查Bot的日志(比如Application Insights),查看是否有存储相关的异常信息
内容的提问来源于stack exchange,提问作者Lanna
相关产品推荐
相关产品推荐

