Bot Framework表单中如何实现用户上传图片附件?
Bot Framework表单实现图片上传的解决方案
当然可以实现Bot Framework表单中的图片上传功能!你遇到的问题主要是两个原因:一是byte类型仅能存储单个字节,完全无法容纳完整的图片二进制数据;二是默认的表单提示逻辑不支持触发文件上传的交互。下面是具体的实现步骤:
1. 修正表单字段类型
首先把图片字段的类型从byte改为byte[],这样才能存储完整的图片二进制数据:
[Serializable] public class VehicleForm { [Prompt("When did this happen")] public DateTime LossDate { get; set; } // 改为byte[]存储图片二进制数据 public byte[] Picture { get; set; } }
2. 用自适应卡片实现文件上传交互
Bot Framework的默认表单输入不支持文件上传,我们需要自定义表单的渲染逻辑,通过**自适应卡片(Adaptive Cards)**的Input.File组件来提供上传入口。
你可以重写表单的OnRenderAsync方法,当渲染到图片字段时,返回包含文件上传组件的自适应卡片:
protected override async Task<Activity> OnRenderAsync(FormContext formContext, object state, CancellationToken cancellationToken) { var baseActivity = await base.OnRenderAsync(formContext, state, cancellationToken); // 判断当前是否渲染图片字段 if (formContext.LastField?.Name == nameof(VehicleForm.Picture)) { var uploadCard = new AdaptiveCard(new AdaptiveSchemaVersion(1, 0)) { Body = new List<AdaptiveElement> { new AdaptiveTextBlock { Text = "请上传证明图片", Size = AdaptiveTextSize.Medium }, new AdaptiveFileInput { Id = "pictureFile", AllowMultipleFiles = false } }, Actions = new List<AdaptiveAction> { new AdaptiveSubmitAction { Title = "确认上传", Data = new { FormAction = "UploadPicture" } } } }; // 替换原活动内容为自适应卡片 baseActivity.Attachments = new List<Attachment> { new Attachment { ContentType = AdaptiveCard.ContentType, Content = uploadCard } }; } return baseActivity; }
3. 处理用户上传的文件数据
当用户提交图片后,需要在Bot的消息处理逻辑中解析上传的文件内容,将其转换为byte[]后赋值给表单的Picture字段。注意不同聊天渠道(如Teams、Web Chat)的文件获取方式略有差异,这里以通用逻辑为例:
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) { var formState = await _formAccessor.GetAsync(turnContext, () => new VehicleForm(), cancellationToken); var formContext = new FormContext<VehicleForm>(turnContext, formState, _formOptions); // 判断是否是图片上传提交 if (turnContext.Activity.Value != null && turnContext.Activity.Value.ToString().Contains("UploadPicture")) { // 获取上传的文件附件 var fileAttachment = turnContext.Activity.Attachments?.FirstOrDefault(a => a.ContentType.StartsWith("image/")); if (fileAttachment != null) { // 从附件中读取二进制数据 using var httpClient = new HttpClient(); var fileStream = await httpClient.GetStreamAsync(fileAttachment.ContentUrl); using var memoryStream = new MemoryStream(); await fileStream.CopyToAsync(memoryStream); formState.Picture = memoryStream.ToArray(); // 手动推进表单到下一个步骤 await formContext.ContinueAsync(cancellationToken); } } else { // 处理普通表单输入 await formContext.ContinueAsync(cancellationToken); } await _formAccessor.SetAsync(turnContext, formState, cancellationToken); }
注意事项
- 不同渠道(如Teams)的文件
ContentUrl可能需要权限验证,你可能需要使用渠道特定的API来获取文件内容; - 可以根据需求限制上传文件的类型(如仅允许jpg/png)和大小,避免过大文件导致性能问题。
内容的提问来源于stack exchange,提问作者Oluwatosin Samuel Babalola




