Reputation: 4606
I am using Bot Framework SDK v-4.x based on .Net Core. I have couple of dialogs created which I am able to flow through using DialogContext.Begin
, DialogContext.End
and DialogContext.Continue
. Everything works fine, but now I want to implement a FormFlow in the middle of a conversation. I referred this link- https://learn.microsoft.com/en-us/azure/bot-service/dotnet/bot-builder-dotnet-formflow?view=azure-bot-service-3.0
I posted this on Github (https://github.com/MicrosoftDocs/bot-docs/issues/227) and based on the solution this is what I tried-
[Serializable]
public class HelpForm
{
public string FullName { get; set; }
public string EmailID { get; set; }
public string Question { get; set; }
public DateTime BestTimeToContact { get; set; }
public List<Priority> Priority { get; set; }
public static IForm<HelpForm> BuildForm()
{
return new FormBuilder<HelpForm>()
.Message("Please fill out the details as prompted.")
.Build();
}
}
public enum Priority
{
Low,
Medium,
High
}
In my OnTurn
event of my bot, I am doing something like this-
await Microsoft.Bot.Builder.Classic.Dialogs.Conversation.SendAsync(context, () => FormDialog.FromForm(HelpForm.BuildForm)); //context is of type ITurnContext
This doesn't seem to work and I get a response in the emulator as
Sorry, my bot code is having an issue.
Also, this link- https://github.com/Microsoft/botbuilder-dotnet/wiki/Using-Classic-V3-Dialogs-with-V4-SDK says that Microsoft.Bot.Builder.Classic
is not supported in .Net Core.
Any help with this please?
Update
Based on Fei's comment, I got the exception details. System.Runtime.Serialization.SerializationException: Type 'System.RuntimeType' in Assembly 'System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e' is not marked as serializable.
. Although my HelpForm class is marked with Serializable
.
Looking at the metadata for FormFlow
class it is not marked with Serializable
attribute.
Note sure if that is what the error is about.
Upvotes: 3
Views: 1422
Reputation: 230
Check this thread.
The Bot Builder Community has released a FormFlow implementation for V4: -
https://www.nuget.org/packages/Bot.Builder.Community.Dialogs.FormFlow/ with source here:
Upvotes: 2
Reputation: 8292
Bot Builder V3 FormFlow dialogs can now be used in the context of a V4 bot by using the recently released Bot.Builder.Community.Dialogs.FormFlow library.
Your HelpForm can be added to a V4 DialogSet in the same way as other V4 ComponentDialogs:
_dialogs.Add(FormDialog.FromForm(HelpForm.BuildForm));
Here is a more complete example:
Accessors:
public class TestEchoBotAccessors
{
public TestEchoBotAccessors(ConversationState conversationState)
{
ConversationState = conversationState ?? throw new ArgumentNullException(nameof(conversationState));
}
public ConversationState ConversationState { get; }
public IStatePropertyAccessor<DialogState> ConversationDialogState { get; set; }
}
Startup.cs ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddBot<TestEchoBotBot>(options =>
{
IStorage dataStore = new MemoryStorage();
options.State.Add(new ConversationState(dataStore));
options.Middleware.Add(new AutoSaveStateMiddleware(options.State.ToArray()));
var secretKey = Configuration.GetSection("botFileSecret")?.Value;
var botFilePath = Configuration.GetSection("botFilePath")?.Value;
// Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection.
var botConfig = BotConfiguration.Load(botFilePath ?? @".\TestEchoBot.bot", secretKey);
services.AddSingleton(sp => botConfig ?? throw new InvalidOperationException($"The .bot config file could not be loaded. ({botConfig})"));
// Retrieve current endpoint.
var environment = _isProduction ? "production" : "development";
var service = botConfig.Services.Where(s => s.Type == "endpoint" && s.Name == environment).FirstOrDefault();
if (!(service is EndpointService endpointService))
{
throw new InvalidOperationException($"The .bot file does not contain an endpoint with name '{environment}'.");
}
options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);
});
services.AddSingleton(sp =>
{
var options = sp.GetRequiredService<IOptions<BotFrameworkOptions>>().Value;
var conversationState = options.State.OfType<ConversationState>().FirstOrDefault();
var accessors = new TestEchoBotAccessors(conversationState)
{
ConversationDialogState = conversationState.CreateProperty<DialogState>("DialogState")
};
return accessors;
});
}
Bot code:
public class TestEchoBotBot : IBot
{
private readonly TestEchoBotAccessors _accessors;
private DialogSet _dialogs;
public TestEchoBotBot(TestEchoBotAccessors accessors, ILoggerFactory loggerFactory)
{
if (loggerFactory == null)
{
throw new System.ArgumentNullException(nameof(loggerFactory));
}
_dialogs = new DialogSet(accessors.ConversationDialogState);
_dialogs.Add(FormDialog.FromForm(HelpForm.BuildForm));
_accessors = accessors ?? throw new System.ArgumentNullException(nameof(accessors));
}
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
if (turnContext.Activity.Type == ActivityTypes.Message)
{
var dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken);
if (turnContext.Activity.Text?.ToUpper() == "HELP")
{
await dialogContext.BeginDialogAsync(typeof(HelpForm).Name, null, cancellationToken);
}
else
{
var dialogResult = await dialogContext.ContinueDialogAsync(cancellationToken);
if ((dialogResult.Status == DialogTurnStatus.Cancelled || dialogResult.Status == DialogTurnStatus.Empty))
{
var responseMessage = $"You sent '{turnContext.Activity.Text}'\n";
await turnContext.SendActivityAsync(responseMessage);
}
}
}
}
}
Upvotes: 2
Reputation: 1347
Unfortunately, as you've discovered, FormFlow doesn't work with v4.
V4 comes with a very structured waterfall dialog however, and this can be used to implement a functionality similar to FormFlow. The sample here shows how to use waterfall dialogs to ask a user a series of questions such as name, age and address. The Prompt dialog class in particular is suited for this type of task. There is a confirm prompt included that you can implement at the end of the dialog to mimic FormFlow's confirmation.
Upvotes: 2