在Microsoft Bot Framework中读取用户字符串列表及客户技能收集表单咨询
Hey there! Let's tackle your chatbot project questions—first fixing that form model code, then covering how to collect a list of skills from users in Microsoft Bot Framework.
ExperiencedDetailFormModel Code I spotted a syntax issue in your current code: the last [Prompt] attribute isn't closed, and you're missing the getter/setter for that final property. Also, if you want to collect skills directly in the form, you can add a dedicated property for that. Here's the corrected, expanded version:
[Serializable] public class ExperiencedDetailFormModel { [Prompt("Please enter your {&}")] public string EducationalQualification { get; set; } [Prompt("Please enter name of your {&}")] public string CurrentOrganization { get; set; } [Prompt("Please enter your {&}")] public string CurrentPositionInTheOrganization { get; set; } // Add this property to collect raw skill input (we'll process it into a list later) [Prompt("Please list your skills separated by commas (e.g., C#, Python, SQL)")] public string SkillsInput { get; set; } }
Quick note: The {&} in the Prompt attribute automatically inserts the property's name into the prompt text, which keeps your code DRY and consistent.
There are three common, user-friendly ways to collect a list of skills (or any string list) from users—pick the one that fits your bot's flow best:
Option 1: Single Text Input with Delimiter
Ask users to enter all skills in one message separated by commas (or another delimiter), then split the input into a list. This works great for quick, straightforward input:
Example in a Waterfall Dialog
// Prompt the user for skills private async Task<DialogTurnResult> GetSkillsStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { return await stepContext.PromptAsync( "textPrompt", new PromptOptions { Prompt = MessageFactory.Text("Please list your skills separated by commas (e.g., C#, Python, SQL)") }, cancellationToken); } // Process the input into a list private async Task<DialogTurnResult> ProcessSkillsStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var rawSkillsInput = (string)stepContext.Result; // Split, clean up whitespace, and remove empty entries List<string> userSkills = rawSkillsInput.Split(',') .Select(skill => skill.Trim()) .Where(skill => !string.IsNullOrEmpty(skill)) .ToList(); // Save to your form model if needed var formModel = (ExperiencedDetailFormModel)stepContext.Options; formModel.SkillsInput = rawSkillsInput; // Store raw input, or track the list separately // Continue your dialog flow return await stepContext.NextAsync(userSkills, cancellationToken); }
Option 2: Collect Skills One-by-One
If you want to guide users to enter skills individually (and let them stop when done), use a loop in your waterfall dialog:
Example Loop Flow
// Initialize list and prompt for first skill private async Task<DialogTurnResult> CollectSingleSkillStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { if (!stepContext.Values.ContainsKey("UserSkills")) { stepContext.Values["UserSkills"] = new List<string>(); } return await stepContext.PromptAsync( "textPrompt", new PromptOptions { Prompt = MessageFactory.Text("Enter one of your skills, or type 'done' when you're finished") }, cancellationToken); } // Process each skill and loop until user says "done" private async Task<DialogTurnResult> ProcessSingleSkillStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var skillInput = (string)stepContext.Result; var userSkills = (List<string>)stepContext.Values["UserSkills"]; if (skillInput.Equals("done", StringComparison.OrdinalIgnoreCase)) { if (userSkills.Count == 0) { await stepContext.Context.SendActivityAsync(MessageFactory.Text("You haven't entered any skills yet—let's try again!"), cancellationToken); return await stepContext.ReplaceDialogAsync(nameof(CollectSingleSkillStepAsync), null, cancellationToken); } // Move to next step with the full skills list return await stepContext.NextAsync(userSkills, cancellationToken); } else { userSkills.Add(skillInput.Trim()); await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Added skill: {skillInput.Trim()}. Enter another or type 'done'."), cancellationToken); return await stepContext.ReplaceDialogAsync(nameof(CollectSingleSkillStepAsync), null, cancellationToken); } }
Option 3: Use Adaptive Cards for Visual Input
For a more polished experience, use an Adaptive Card with multiple input fields. Users can fill in skills directly, and you can parse the submitted values into a list:
Example Adaptive Card (JSON)
{ "type": "AdaptiveCard", "version": "1.0", "body": [ { "type": "TextBlock", "text": "Tell us about your skills", "size": "Large", "weight": "Bolder" }, { "type": "Input.Text", "id": "skill1", "placeholder": "Skill 1 (e.g., JavaScript)" }, { "type": "Input.Text", "id": "skill2", "placeholder": "Skill 2 (optional)" }, { "type": "Input.Text", "id": "skill3", "placeholder": "Skill 3 (optional)" } ], "actions": [ { "type": "Action.Submit", "title": "Submit Skills" } ] }
Parse Card Submission in Dialog
// Send the Adaptive Card to the user private async Task<DialogTurnResult> GetSkillsViaCardStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var cardAttachment = new Attachment { ContentType = "application/vnd.microsoft.card.adaptive", Content = JsonConvert.DeserializeObject(/* Insert your Adaptive Card JSON string here */) }; var promptOptions = new PromptOptions { Prompt = MessageFactory.Attachment(cardAttachment) }; return await stepContext.PromptAsync("adaptiveCardPrompt", promptOptions, cancellationToken); } // Process the submitted card values into a list private async Task<DialogTurnResult> ProcessCardSkillsStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var submittedValues = (IDictionary<string, object>)stepContext.Result; List<string> userSkills = new List<string>(); // Collect non-empty skill inputs for (int i = 1; i <= 3; i++) { if (submittedValues.TryGetValue($"skill{i}", out var skillObj) && skillObj is string skill && !string.IsNullOrEmpty(skill.Trim())) { userSkills.Add(skill.Trim()); } } // Use the skills list in your bot logic return await stepContext.NextAsync(userSkills, cancellationToken); }
内容的提问来源于stack exchange,提问作者Akbar Badhusha

