C# Bot框架:检测用户何时上载文件

C# Bot框架:检测用户何时上载文件,c#,.net,file-upload,botframework,C#,.net,File Upload,Botframework,我正在尝试在我的bot中创建一个表单,其中用户必须上传一个文件以及其他文本输入。为此,我制作了一个ReceiveAttachmentDialog,在其中它将验证用户是否上传了文件,问题是我不知道如何检测用户何时上传了文件,从而使用ReceiveAttachmentDialo 福特对话是这样的: [Serializable] public class FraisDialog : IDialog<object> { public async Task S

我正在尝试在我的bot中创建一个表单,其中用户必须上传一个文件以及其他文本输入。为此,我制作了一个ReceiveAttachmentDialog,在其中它将验证用户是否上传了文件,问题是我不知道如何检测用户何时上传了文件,从而使用ReceiveAttachmentDialo

福特对话是这样的:

[Serializable]
    public class FraisDialog : IDialog<object>
    {

        public async Task StartAsync(IDialogContext context)
        {
            // Root dialog initiates and waits for the next message from the user. 
            // When a message arrives, call MessageReceivedAsync.

            var replyMessage = context.MakeMessage();


            replyMessage.Attachments = new List<Connector.Attachment> { CreateAdaptiveCardwithEntry() };
            await context.PostAsync("Veuillez compléter le formulaire ci-dessous");
            await context.PostAsync(replyMessage, CancellationToken.None);
            context.Wait(this.MessageReceivedAsync);
        }


        public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
        {

            context.Wait(MessageReceivedAsync);
            var message = await result;

            if (message.Value != null)
            {
                // Got an Action Submit
                dynamic value = message.Value;
                string submitType = value.Type.ToString();
                switch (submitType)
                {
                    case "SaveFunction":
                        if (value.titre == "")
                        {
                            await context.PostAsync("Veuillez compléter tous les paramètres du formulaire \n");
                        }
                        else
                        {
                            await context.PostAsync($"Vous avez saisie les paramètres suivants : \n titre :  {value.titre} \n date : {value.date} \n montant :  {value.montant}");

                           context.Done<string>(null);
                       }
                       return;
                }
            }
       }

        public Connector.Attachment CreateAdaptiveCardwithEntry()
        {
            var submitActionData = JObject.Parse("{ \"Type\": \"SaveFunction\" }");
            var card = new AdaptiveCard()
            {

                Body = new List<CardElement>()
                {  
                    // Hotels Search form  

                    new TextBlock() { Text = "Titre de la note des frais" },
                    new TextInput()
                    {
                        Id = "titre",
                        Speak = "<s>Veuillez saisir le titre</s>",
                        Placeholder = "Veuillez saisir le titre",
                        Style = TextInputStyle.Text
                    },
                    new TextBlock() { Text = "Date de la note des frais" },
                    new DateInput()
                    {
                        Id = "date",
                        Placeholder ="Veuillez saisir la Date de la note des frais"
                    },

                    new TextBlock() { Text = "Montant en euros de la note de frais" },
                    new NumberInput()
                    {
                        Id = "montant",
                        Speak = "<s>Veuillez saisir le Montant en euros de la note de frais</s>",
                        Placeholder = "Veuillez saisir le Montant de la note de frais",

                    },

                },

                Actions = new List<ActionBase>()
                {
                    new SubmitAction()
                    {
                       Title = "Envoyer",
                       Speak = "<s>Envoyer</s>",
                       DataJson = submitActionData.ToString()

                    }
                }
            };

            Connector.Attachment attachment = new Connector.Attachment()
            {
                ContentType = AdaptiveCard.ContentType,
                Content = card
            };
            return attachment;
        }
    }
[可序列化]
公共类FraisDialog:IDialog
{
公共异步任务StartAsync(IDialogContext上下文)
{
//Root对话框启动并等待来自用户的下一条消息。
//消息到达时,请调用MessageReceivedAsync。
var replyMessage=context.MakeMessage();
replyMessage.Attachments=新列表{CreateAptiveCardWithEntry()};
等待上下文。PostAsync(“Veuillez compléter le formulaire ci dessous”);
wait context.PostAsync(replyMessage,CancellationToken.None);
context.Wait(this.MessageReceivedAsync);
}
公共虚拟异步任务消息ReceivedAsync(IDialogContext上下文,IAwaitable结果)
{
Wait(MessageReceivedAsync);
var消息=等待结果;
if(message.Value!=null)
{
//收到一个提交的动作
动态值=message.value;
字符串submitType=value.Type.ToString();
开关(提交类型)
{
案例“SaveFunction”:
如果(value.titre==“”)
{
wait context.PostAsync(“公式化参数的Veuillez compléter tous les paramètres du formulaire\n”);
}
其他的
{
wait context.PostAsync($“Vous avez saisie les paramètres suivants:\n titre:{value.titre}\n date:{value.date}\n montant:{value.montant}”);
context.Done(null);
}
返回;
}
}
}
公共连接器。附件CreateAptiveCardWithEntry()
{
var submitActionData=JObject.Parse(“{\”类型\“:\”保存函数\“}”);
var卡=新的自适应卡()
{
Body=新列表()
{  
//酒店查询表格
新建TextBlock(){Text=“Titre de la note des frais”},
新文本输入()
{
Id=“titre”,
Speak=“Veuillez Saiser le titre”,
占位符=“Veuillez saisir le titre”,
Style=TextInputStyle.Text
},
new TextBlock(){Text=“票据日期”},
新日期输入()
{
Id=“日期”,
占位符=“发票日期”
},
新的TextBlock(){Text=“Montant en euros de la note de frais”},
新号码输入()
{
Id=“montant”,
Speak=“Veuillez Saiser le Montant en euros de la note de frais”,
占位符=“Veuillez saisir le Montant de la note de frais”,
},
},
操作=新列表()
{
新提交
{
Title=“特使”,
Speak=“特使”,
DataJson=submitActionData.ToString()
}
}
};
Connector.Attachment附件=新的Connector.Attachment()
{
ContentType=AdaptiveCard.ContentType,
内容=卡片
};
返回附件;
}
}

我的问题是如何检测用户何时上传了文件?我应该把wait context.Forward(new ReceiveAttachmentDialog(),this.resumeAfterReceiveDialog,context.Activity,CancellationToken.None)放在哪里

如果您还没有使用FormFlow,我建议您使用FormFlow,并检查找到的示例和表单本身

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Threading.Tasks;

using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.FormFlow;
using Microsoft.Bot.Builder.FormFlow.Advanced;
using Microsoft.Bot.Connector;

namespace Microsoft.Bot.Sample.FormFlowAttachmentsBot
{
    [Serializable]
    public class MyAwaitableImage : AwaitableAttachment
    {
        // Mandatory: you should have this ctor as it is used by the recognizer
        public MyAwaitableImage(Attachment source) : base(source) { }

        // Mandatory: you should have this serialization ctor as well & call base
        protected MyAwaitableImage(SerializationInfo info, StreamingContext context) : base(info, context) { }

        // Optional: here you can check for content-type for ex 'image/png' or other..
        public override async Task<ValidateResult> ValidateAsync<T>(IField<T> field, T state)
        {
            var result = await base.ValidateAsync(field, state);

            if (result.IsValid)
            {
                var isValidForMe = this.Attachment.ContentType.ToLowerInvariant().Contains("image/png");

                if (!isValidForMe)
                {
                    result.IsValid = false;
                    result.Feedback = $"Hey, dude! Provide a proper 'image/png' attachment, not any file on your computer like '{this.Attachment.Name}'!";
                }
            }

            return result;
        }

        // Optional: here you can provide additional or override custom help text completely..
        public override string ProvideHelp<T>(IField<T> field)
        {
            var help = base.ProvideHelp(field);

            help += $"{Environment.NewLine}- Only 'image/png' can be attached to this field.";

            return help;
        }

        // Optional: here you can define your custom logic to get the attachment data or add custom logic to check it, etc..
        protected override async Task<Stream> ResolveFromSourceAsync(Attachment source)
        {
            var result = await base.ResolveFromSourceAsync(source);

            // You can apply custom logic to result or avoid calling base and resolve it yourself
            // For ex. if you plan to use your instance several times you can return a MemoryStream instead

            return result;
        }
    }

    [Serializable]
    public class ImagesForm
    {
        // Attachment field has no validation - any attachment would work
        public AwaitableAttachment BestImage;

        // Attachment field is optional - validation is done through AttachmentContentTypeValidator usage
        [Optional]
        [AttachmentContentTypeValidator(ContentType = "png")]
        public AwaitableAttachment SecondaryImage;

        // You can use an AwaitableAttachment descendant in order to have your own custom logic
        public IEnumerable<MyAwaitableImage> CustomImages;

        public static IForm<ImagesForm> BuildForm()
        {
            OnCompletionAsyncDelegate<ImagesForm> onFormCompleted = async (context, state) =>
            {
                await context.PostAsync("Here is a summary of the data you submitted:");

                var bestImageSize = await RetrieveAttachmentSizeAsync(state.BestImage);
                await context.PostAsync($"Your best image is '{state.BestImage.Attachment.Name}' - Type: {state.BestImage.Attachment.ContentType} - Size: {bestImageSize} bytes");

                if (state.SecondaryImage != null)
                {
                    var secondaryImageSize = await RetrieveAttachmentSizeAsync(state.SecondaryImage);
                    await context.PostAsync($"Your secondary image is '{state.SecondaryImage.Attachment.Name}' - Type: {state.SecondaryImage.Attachment.ContentType} - Size: {secondaryImageSize} bytes");
                }
                else
                {
                    await context.PostAsync($"You didn't submit a secondary image");
                }

                var customImagesTextInfo = string.Empty;
                foreach (var image in state.CustomImages)
                {
                    var imgSize = await RetrieveAttachmentSizeAsync(image);
                    customImagesTextInfo += $"{Environment.NewLine}- Name: '{image.Attachment.Name}' - Type: {image.Attachment.ContentType} - Size: {imgSize} bytes";
                }

                await context.PostAsync($"Here is the info of custom images you submitted: {customImagesTextInfo}");
            };

            // Form localization is done by setting the thread culture
            System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-us");

            return new FormBuilder<ImagesForm>()
                .Message("Welcome, please submit all required images")
                .OnCompletion(onFormCompleted)
                .Build();
        }

        private static async Task<long> RetrieveAttachmentSizeAsync(AwaitableAttachment attachment)
        {
            var stream = await attachment;
            return stream.Length;
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.IO;
使用System.Runtime.Serialization;
使用System.Threading.Tasks;
使用Microsoft.Bot.Builder.Dialogs;
使用Microsoft.Bot.Builder.FormFlow;
使用Microsoft.Bot.Builder.FormFlow.Advanced;
使用Microsoft.Bot.Connector;
命名空间Microsoft.Bot.Sample.FormFlowAttachmentsBot
{
[可序列化]
公共类MyAwatiableImage:AwatiableAttachment
{
//必填项:识别器使用此ctor时,您应该使用此ctor
公共MyAwaitableImage(附件源):基(源){}
//必填项:您还应该具有此序列化构造函数&callbase
受保护的MyAwaitableImage(SerializationInfo,StreamingContext上下文):基(info,context){}
//可选:您可以在此处检查ex'image/png'或其他的内容类型。。
公共覆盖异步任务ValidateAsync(IField字段,T状态)
{
var result=await base.ValidateAsync(字段、状态);
if(result.IsValid)
{
var isValidForMe=this.Attachment.ContentType.ToLowerInvariant().Contains(“image/png”);
如果(!isValidForMe)
{
result.IsValid=false;
result.Feedback=$“嘿,伙计!提供一个正确的‘image/png’附件,而不是计算机上任何类似于{this.attachment.Name}的文件!”;
}
}
返回结果;
}
//可选:您可以在此处提供附加或覆盖自定义帮助文本
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
using System;
using System.Linq;
using System.Net;
using System.Threading.Tasks;

namespace Bot_Application1.Dialogs
{
    [Serializable]
    public class RootDialog : IDialog<object>
    {
        public Task StartAsync(IDialogContext context)
        {
            context.Wait(MessageReceivedAsync);

            return Task.CompletedTask;
        }

        private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
        {
            var activity = await result as Activity;

            if (activity.Attachments.Any())
            {
                //do something with the file
                //it looks like this is where you would put your 
                //context.Forward() 
                await context.Forward(new ReceiveAttachmentDialog(), this.ResumeAfterRecieveDialog, context.Activity, CancellationToken.None);

                await context.PostAsync($"you sent a file");
            }
            else
            {
                await context.PostAsync($"No File received");
            }
            context.Wait(MessageReceivedAsync);
        }
    }
}