如何在Bot Framework Composer中实现机器人向聊天用户发送可下载Excel文件?
我之前在做Composer机器人时也碰到过这个问题,官方确实没直接提供文件下载的可视化组件,但通过扩展自定义动作或者利用Bot Framework的底层能力完全可以实现,给你分享几个靠谱的方案:
方案一:在自定义动作中直接发送文件附件
既然你已经能通过自定义动作生成Excel文件,那可以在同一个自定义动作里直接构建带附件的消息发给用户,核心是利用Bot Framework的Activity对象添加附件。
具体步骤:
- 在你的自定义动作代码中,生成Excel文件后,将文件内容转为Base64字符串或者直接获取文件流。
- 创建
Attachment对象,指定正确的MIME类型(Excel文件用application/vnd.openxmlformats-officedocument.spreadsheetml.sheet),并填入文件名和内容。 - 构造包含该附件的
Activity,调用turnContext.SendActivityAsync()发送给用户。
代码示例(C#):
using Microsoft.Bot.Builder; using Microsoft.Bot.Schema; using System.IO; using System.Threading.Tasks; public class SendExcelAttachmentAction : Dialog { public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, System.Threading.CancellationToken cancellationToken = default) { // 这里是你已有的生成Excel文件的逻辑,假设生成后得到fileStream var fileStream = GenerateExcelFile(); // 你的生成方法 // 将文件流转为Base64 string base64Content; using (var memoryStream = new MemoryStream()) { fileStream.CopyTo(memoryStream); base64Content = Convert.ToBase64String(memoryStream.ToArray()); } // 创建附件 var attachment = new Attachment { Name = "用户数据.xlsx", ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ContentUrl = $"data:{attachment.ContentType};base64,{base64Content}" }; // 构造消息并发送 var reply = MessageFactory.Attachment(attachment); await dc.Context.SendActivityAsync(reply, cancellationToken); return await dc.EndDialogAsync(cancellationToken: cancellationToken); } // 你的Excel生成方法示例 private Stream GenerateExcelFile() { // 这里是你生成Excel的逻辑,返回文件流 var stream = new MemoryStream(); // ... 生成Excel的代码 return stream; } }
方案二:上传文件到云存储,发送下载链接
如果Excel文件比较大,直接发Base64附件可能会有性能问题,建议先把文件上传到云存储(比如Azure Blob Storage、AWS S3等),然后生成一个临时下载链接,通过消息或者自适应卡片发送给用户。
具体步骤:
- 在自定义动作中生成Excel文件后,上传到云存储服务,获取带有效期的下载链接(比如Azure Blob的SAS链接)。
- 用
MessageFactory.Text()发送包含链接的文本消息,或者用自适应卡片做一个更友好的下载按钮。
自适应卡片示例(JSON):
{ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "type": "AdaptiveCard", "version": "1.0", "body": [ { "type": "TextBlock", "text": "你的Excel文件已生成,点击下方按钮下载:" } ], "actions": [ { "type": "Action.OpenUrl", "title": "下载Excel", "url": "这里替换为你的云存储下载链接" } ] }
你可以在自定义动作中构造这个自适应卡片,然后通过MessageFactory.Attachment(new Attachment { ContentType = AdaptiveCard.ContentType, Content = adaptiveCardJson })发送。
方案三:利用Composer的"Send a response"组件+自定义模板
如果你不想写太多代码,也可以在Composer的“Send a response”组件中使用自定义模板,直接引用你生成的文件Base64内容。不过这种方式需要先把文件的Base64存在对话状态里,然后在响应模板中插入。
比如在自定义动作中将文件Base64和文件名存入turn.State:
turn.State["excelBase64"] = base64Content; turn.State["excelFileName"] = "用户数据.xlsx";
然后在Composer的响应模板中写:
[Attachment Name=${turn.state.excelFileName} ContentType=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet ContentUrl=data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,${turn.state.excelBase64} ]
这三个方案里,方案一适合小文件,方案二适合大文件,方案三更贴合Composer的可视化开发流程,你可以根据自己的场景选择~
内容的提问来源于stack exchange,提问作者Aayush Gupta

