我在下面有以下示例类,它从context.UserData启动FirstName和emailAddress的值。
当我调用表单时这很有效,所以我没有被要求使用FirstName或emailAddress,因为我总是在测试时设置它。
但是,如果我输入RESET,FormDialog会自动处理,我的调试器不会进入StartAsync(),我有一个断点。然后我被要求提供我的FirstName,即使它已经可用。
我是否在StartAsync()中正确初始化数据?即使调用RESET,我如何使它坚持下去?
我意识到的一个奇怪的事情是,如果我发表评论.Field(nameof(AdultOptionCount)
和.Field(nameof(ChildOptionCount)
,那么RESET不会要求我提供我的名字。
以下是我使用的完整代码,它总是要求重置后的FirstName。
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.FormFlow;
using Microsoft.Bot.Connector;
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace MyDialogs
{
[Serializable]
public class RootDialog : IDialog<object>
{
public RootDialog()
{
}
public async Task StartAsync(IDialogContext context)
{
//This is a test so I am filling up CustomerAccount data here
CustomerAccount ca = new CustomerAccount();
ca.FirstName = "Oyen";
ca.Email = "oyen@email.com";
context.UserData.SetValue<CustomerAccount>("CustomerAccount", ca);
context.Wait(this.MessageReceivedAsync);
}
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
{
//this message is always ignored
var message = await result;
await context.PostAsync("Hello there! Let's get started.");
//a bunch of questions are usually asked here to determine which LUIS Dialog I will call because I have several
//right now, let's just go straight to the Application dialog
var app = new MyApplication();
context.Call(app, ApplicationResumeAfter);
}
private async Task ApplicationResumeAfter(IDialogContext context, IAwaitable<object> result)
{
var message = await result;
//do nothing else in this test
context.Done(true);
}
}
[Serializable]
public class CustomerAccount
{
public string FirstName { get; set; }
public string Email { get; set; }
}
[Serializable]
public class MyApplication : IDialog<string>
{
public async Task StartAsync(IDialogContext context)
{
context.Call(new ApplyForm(), CompleteApplication);
}
private async Task CompleteApplication(IDialogContext context, IAwaitable<object> result)
{
var message = await result;
context.Done("SUCCESSFUL");
}
}
[Serializable]
public class ApplyForm : IDialog<ApplyForm>
{
public async Task StartAsync(IDialogContext context)
{
var state = new ApplyForm();
CustomerAccount CustomerAccount;
if (context.UserData.TryGetValue<CustomerAccount>("CustomerAccount", out CustomerAccount))
{
state.FirstName = CustomerAccount.FirstName;
state.EmailAddress = CustomerAccount.Email;
}
var form = new FormDialog<ApplyForm>(
state,
BuildForm,
FormOptions.PromptInStart);
context.Call(form, this.AfterBuildForm);
}
[Prompt("What is your **{&}**?")]
public string FirstName { get; set; }
[Prompt("What is your **{&}**?")]
public string EmailAddress;
[Numeric(0, 15)]
[Prompt("How many adults will attend?")]
public int AdultOptionCount { get; set; }
[Numeric(0, 15)]
[Prompt("How many children will attend?")]
public int ChildOptionCount { get; set; }
public static IForm<ApplyForm> BuildForm()
{
var form = new FormBuilder<ApplyForm>()
.Field(nameof(FirstName),
active: (state) =>
{
return string.IsNullOrEmpty(state.FirstName);
})
.Field(nameof(EmailAddress),
active: (state) =>
{
return string.IsNullOrEmpty(state.EmailAddress);
})
.Field(nameof(AdultOptionCount),
validate: async (state, value) =>
{
var result = new ValidateResult { Value = value };
result.IsValid = IsInteger(value);
return result;
})
.Field(nameof(ChildOptionCount),
validate: async (state, value) =>
{
var result = new ValidateResult { Value = value };
result.IsValid = IsInteger(value);
return result;
})
.Build();
return (IForm<ApplyForm>)form;
}
private async Task AfterBuildForm(IDialogContext context, IAwaitable<ApplyForm> result)
{
context.Done(result);
}
private static bool IsInteger(object value)
{
try
{
var s = value.ToString();
int n;
if (int.TryParse(s, out n))
return true;
}
catch (Exception ex)
{
throw ex;
}
return false;
}
}
}
答案 0 :(得分:1)
感谢您的演示,我最后重现了您的问题并理解问题是在reset
之后,如果第一个字段上有active
条件,它将忽略它并仍然提示第一个字段领域。
输入StartAsync
时,实际再次调用reset
方法,因此您已成功设置默认值。这可以通过在完成整个流程之后检查结果来证明,即使第一个字段再次被询问并且用户输入该字段的另一个值,它仍然将提交StartAsync
中获得的预设值。作为最终结果。
所以为了避免这个问题,我只能建议暂时不要在FormFlow
的第一个字段中提示有条件激活的字段,这意味着有很多解决方法可以解决这个问题,但解决方案基于这个想法似乎并不优雅。
例如,以下是一种解决方法:根据预设FormFlow
使用不同的CustomerAccount
:
public async Task StartAsync(IDialogContext context)
{
var state = new ApplyForm();
CustomerAccount customerAccount;
FormDialog<ApplyForm> form;
if (context.UserData.TryGetValue<CustomerAccount>("CustomerAccount", out customerAccount))
{
state.FirstName = customerAccount.FirstName;
state.EmailAddress = customerAccount.Email;
form = new FormDialog<ApplyForm>(
state,
BuildForm2,
FormOptions.PromptInStart);
}
else
{
form = new FormDialog<ApplyForm>(
state,
BuildForm1,
FormOptions.PromptInStart);
}
context.Call(form, this.AfterBuildForm);
}
[Prompt("What is your **{&}**?")]
public string FirstName { get; set; }
[Prompt("What is your **{&}**?")]
public string EmailAddress { get; set; }
[Numeric(0, 15)]
[Prompt("How many adults will attend?")]
public int AdultOptionCount { get; set; }
[Numeric(0, 15)]
[Prompt("How many children will attend?")]
public int ChildOptionCount { get; set; }
public static IForm<ApplyForm> BuildForm1()
{
var form = new FormBuilder<ApplyForm>()
.Field(nameof(FirstName))
.Field(nameof(EmailAddress))
.Field(nameof(AdultOptionCount),
validate: async (state, value) =>
{
var result = new ValidateResult { Value = value };
result.IsValid = IsInteger(value);
return result;
})
.Field(nameof(ChildOptionCount),
validate: async (state, value) =>
{
var result = new ValidateResult { Value = value };
result.IsValid = IsInteger(value);
return result;
})
.Build();
return (IForm<ApplyForm>)form;
}
public static IForm<ApplyForm> BuildForm2()
{
var form = new FormBuilder<ApplyForm>()
.Field(nameof(AdultOptionCount),
validate: async (state, value) =>
{
var result = new ValidateResult { Value = value };
result.IsValid = IsInteger(value);
return result;
})
.Field(nameof(ChildOptionCount),
validate: async (state, value) =>
{
var result = new ValidateResult { Value = value };
result.IsValid = IsInteger(value);
return result;
})
.Build();
return (IForm<ApplyForm>)form;
}
//other code goes here
这种解决方法是不合理的,因为它在构建active
时放弃了Field
FormFlow
条件的使用。
与此同时,我已提交此问题,如果我收到任何新信息,我会更新我的答案。感谢您分享您的演示。