2017-05-09 47 views
0

我開發了一個BOT應用程序,我已經使用表單流向用戶詢問一組問題。現在我有要求在用戶輸入無效選項超過3次時捕獲事件。我發現PromoDialog的TooManyAttemptsException類,但找不到相同的FormDialog。有什麼方法可以捕獲太多的嘗試,並阻止用戶在FormDialog中進一步嘗試?Microsoft Bot:如何捕獲表單流中的太多嘗試?

//示例代碼

{ 
    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

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項目中找到此代碼。

+0

感謝您的建議。在你的情況「Version」字段是字符串,所以當用戶給這個字段的任何放,驗證方法被調用。在我的情況下,該字段是Enum類型。所以「validate:」方法根本不被調用,而是直接給出錯誤信息。對於那裏有預定義選項的枚舉類型字段,驗證方法沒有被調用。 – user1899731

+0

這是我的枚舉字段[提示(「您是現有客戶嗎?{||}」,ChoiceFormat =「{1}」)] [模板(TemplateUsage.NotUnderstood,「我不明白\」{0} \ 「。」,「再試一次,我不會得到\」{0} \「。」)] public CustomerTypeOptions?客戶類型;我直接獲取模板消息 – user1899731