我开发了一个BOT应用程序,我使用表单流向用户提出一组问题。现在我需要在用户输入无效选项超过3次时捕获事件。我找到了PromptDialog的TooManyAttemptsException类,但找不到FormDialog的相同内容。有没有办法捕获太多的尝试并阻止用户在FormDialog中进一步尝试?
//示例代码
{
var enrollmentForm = new FormDialog<AppointmentQuery>(new Models.AppointmentQuery(), AppointmentForm.BuildForm, FormOptions.PromptInStart);
context.Call<AppointmentQuery>(enrollmentForm, this.ResumeAfterOptionDialog);
private async Task ResumeAfterOptionDialog(IDialogContext context, IAwaitable<AppointmentQuery> result)
{
try
{
var message = await result;
}
catch (FormCanceledException e)
{
string reply = string.Empty;
await this.StartOverAsync(context, reply);
}
catch (TooManyAttemptsException et)
{
await context.PostAsync($"Ooops! Too many attemps :(. But don't worry, I'm handling that exception and you can try again!");
await this.StartOverAsync(context, "");
}
catch (Exception ex)
{
await context.PostAsync($"Failed with message: {ex.Message}");
}
finally
{
context.Wait(this.MessageReceivedAsync);
}
}
}
答案 0 :(得分:0)
FormFlow不会抛出TooManyAttemptsException
。但是,解决方法是执行您自己的字段验证,如下所示:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Microsoft.Bot.Builder.FormFlow;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.FormFlow.Advanced;
using System.Threading.Tasks;
namespace BugFormFlowBot2
{
[Serializable]
[Template(TemplateUsage.EnumSelectOne, "Which {&} were you working with? {||}")]
[Template(TemplateUsage.EnumSelectMany, "Which {&} were you working with? {||}", ChoiceStyle = ChoiceStyleOptions.PerLine)]
public class BugReport
{
public string Product { get; set; }
public string Version { get; set; }
public List<PlatformOptions> Platform { get; set; }
[Prompt("What is the {&}")]
[Describe("Description of the Problem")]
public string ProblemDescription { get; set; }
[Numeric(1, 3)]
public int Priority { get; set; }
private static int versionAttempts = 0;
public static IForm<BugReport> BuildForm()
{
return new FormBuilder<BugReport>()
.Message("Welcome to Bug Report bot!")
.Field(new FieldReflector<BugReport>(nameof(Product))
.SetType(null)
.SetDefine((state, field) =>
{
foreach (var prod in GetProducts())
field
.AddDescription(prod, prod)
.AddTerms(prod, prod);
return Task.FromResult(true);
}))
.Field(nameof(Version),
validate: async (state, response) =>
{
var result = new ValidateResult { IsValid = true, Value = response };
foreach (var segment in (response as string ?? "").Split('.'))
{
int digit;
if (!int.TryParse(segment, out digit))
{
result.Feedback =
"Version number must be numeric segments, optionally separated by dots. e.g. 7.2, 10, or 3.56";
result.IsValid = false;
if (++versionAttempts > 2)
throw new TooManyAttemptsException("Too many attempts at the version number.");
break;
}
}
return await Task.FromResult(result);
})
.Field(nameof(Platform))
.AddRemainingFields()
.Confirm(async (bugReport) =>
{
var response = new PromptAttribute(
$"You entered {bugReport.Product}, {bugReport.Version}, {bugReport.Platform}" +
$"{bugReport.ProblemDescription}, {bugReport.Priority}. Is this Correct?");
return await Task.FromResult(response);
})
.OnCompletion(async (context, bugReport) =>
{
await context.PostAsync("Thanks for the report!");
})
.Build();
}
static List<string> GetProducts()
{
return new List<string>
{
"Office",
"SQL Server",
"Visual Studio"
};
}
}
}
注意versionAttempts
字段是private static
的方式。然后查看Version
字段的验证以及它如何抛出TooManyAttemptsException
。
这并不能完全解决问题,因为FormFlow会在FormCanceledException
中包装所有异常。以下代码显示了如何处理它。
using System;
using System.Threading.Tasks;
using System.Web.Http;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.FormFlow;
using System.Net.Http;
using System.Net;
namespace BugFormFlowBot2
{
[BotAuthentication]
public class MessagesController : ApiController
{
internal static IDialog<BugReport> MakeRootDialog()
{
return Chain.From(() => FormDialog.FromForm(BugReport.BuildForm))
.Loop();
}
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity?.Type == ActivityTypes.Message)
try
{
await Conversation.SendAsync(activity, MakeRootDialog);
}
catch (FormCanceledException fcEx) when(fcEx.InnerException is TooManyAttemptsException)
{
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
Activity reply = activity.CreateReply(
$"Too Many Attempts at {fcEx.Last}. " +
$"Completed Steps: {string.Join(", ", fcEx.Completed)}");
await connector.Conversations.ReplyToActivityAsync(reply);
}
catch (FormCanceledException fcEx)
{
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
Activity reply = activity.CreateReply(
$"Form cancelled at {fcEx.Last}. " +
$"Completed Steps: {string.Join(", ", fcEx.Completed)}");
await connector.Conversations.ReplyToActivityAsync(reply);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
}
}
使用FormCanceledException
注意Post
中的when(fcEx.InnerException is TooManyAttemptsException)
处理程序,以便了解TooManyAttemptsException
何时发生。有趣的是,FormCanceledException
提供了有关已完成字段的更多信息,为您提供有关异常时表单状态的更多信息。
您可以在我的BotDemos GitHub存储库中的BugFormFlowBot2项目中找到此代码。