мы разработали BOT с использованием Microsoft Bot Framework 3.0 с некоторым диалогом, связывающим друг друга с Context.Wait (Метод).
Каждый публикует сообщение и устанавливает другой метод диалога в ожидании следующего сообщения.
Пример кода
Наш контроллер сообщений:
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.GetActivityType() == ActivityTypes.ConversationUpdate)
{
if (activity.MembersAdded.Any(m => m.Id != activity.Recipient.Id))
{
activity.Type = ActivityTypes.Message;
activity.Text = _startGreetingsMessage;
}
}
if (activity.GetActivityType() == ActivityTypes.Message)
{
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
{
var dialog = scope.Resolve<IDialog<object>>();
await Conversation.SendAsync(activity, () => dialog);
}
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.Accepted);
return response;
}
Наш RootDialog наследует от Луиса:
[Serializable]
public class RootDialog : LuisDialog<object>
{
private readonly IDialogFactory _dialogFactory;
public RootDialog(ILuisService luisService, IDialogFactory dialogFactory)
: base(luisService)
{
_dialogFactory = dialogFactory;
}
[LuisIntent("None")]
public async Task NoneIntent(IDialogContext context, LuisResult result)
{
await context.PostAsync(MessagesResource.CourtesyError);
context.Call(_dialogFactory.Create<GreetingDialog>(), Callback);
}
[LuisIntent("Greetings")]
public async Task GreetingsIntent(IDialogContext context, LuisResult result)
{
context.Call(_dialogFactory.Create<GreetingDialog>(), Callback);
}
[LuisIntent("CreateNewList")]
public async Task CreateNewListIntent(IDialogContext context, LuisResult result)
{
context.Call(_dialogFactory.Create<CreateNewShoppingListDialog>(), Callback);
}
[LuisIntent("OpenLastList")]
public async Task OpenLastListIntent(IDialogContext context, LuisResult result)
{
context.Call(_dialogFactory.Create<OpenLastShoppingListDialog>(), Callback);
}
[LuisIntent("GetTimetables")]
public async Task GetTimetablesIntent(IDialogContext context, LuisResult result)
{
context.Call(_dialogFactory.Create<OpeningHoursDialog>(), Callback);
}
[LuisIntent("GetPromo")]
public async Task GetPromoIntent(IDialogContext context, LuisResult result)
{
context.Call(_dialogFactory.Create<PromoProductsByCategoryDialog>(), Callback);
}
[LuisIntent("")]
public async Task CancelIntent(IDialogContext context, LuisResult result)
{
await context.PostAsync(MessagesResource.CourtesyError);
context.Call(_dialogFactory.Create<GreetingDialog>(), Callback);
}
private async Task Callback(IDialogContext context, IAwaitable<object> result)
{
await result;
context.Done(true);
}
}
Пример того, как мы видим время ожидания между частями диалога:
[Serializable]
public class AskIfAddAnotherProductTask
{
private readonly IShoppingListsService _shoppingListsService;
private readonly IDialogFactory _dialogFactory;
private readonly ILogger _logger;
public AskIfAddAnotherProductTask(IDialogFactory dialogFactory, IShoppingListsService shoppingListsService, ILogger logger)
{
_shoppingListsService = shoppingListsService;
_dialogFactory = dialogFactory;
_logger = logger;
}
public async Task GetTask(IDialogContext context, IAwaitable<IMessageActivity> result)
{
var userResponse = await result;
var channel = context.Activity.ChannelId;
var dict = new Dictionary<string, object>() { { "context", context } };
var luisResult = await LuisHelper.GetIntentAndEntitiesFromLUIS(userResponse.Text);
switch (luisResult.TopScoringIntent.Intent)
{
case LuisIntent.Yes:
{
await context.PostAsync(MessagesResource.AddOtherProducts);
context.Wait(_dialogFactory.Create<GetProductsByUserTask>().GetTask);
break;
}
case LuisIntent.No:
{
var sender = _dialogFactory.Create<SendCorrectYesOrNoCard>(dict);
await sender.Send(channel, MessagesResource.AskIfWantSuggestions);
var handler = _dialogFactory.Create<HandleUserIncorrectInput>(dict);
handler.ResetCounter();
context.Wait(_dialogFactory.Create<AskIfWantSuggestionProductsTask>().GetTask);
break;
}
default:
{
await context.PostAsync(MessagesResource.CourtesyChooseError);
var sender = _dialogFactory.Create<SendCorrectYesOrNoCard>(dict);
await sender.Send(channel, MessagesResource.AskIfWantAddProduct);
context.Wait(GetTask);
break;
}
}
}
}
Этапы воспроизведения
Это случайно, особого шага для воспроизведения нет.
Мы столкнулись с проблемой на канале мессенджера Facebook.
Ожидаемое поведение
Всегда вызывайте правильный метод: -)
Фактические результаты
Иногда, случайно, мы сталкивались с тем, что один и тот же «метод в ожидании» вызывается два раза подряд ... что-то не получается при последней вставке метода в ожидании или что-то в этом роде ... ,
У кого-нибудь есть идеи по этому поводу? Мы опробовали несколько вариантов и обойти безуспешно ...
UPDATE:
В основном у нас такая ситуация: RootDialog
-> context.call (DialogA, RootDialogCallback)
-> context.wait ( MethodFromAnotherClass1 ) ....
-> context.wait ( MethodFromAnotherClassN )
-> context.done ()
-> RootDialogCallback
-> context.done ()
Это работает примерно в 70-80% случаев ... Так что мой вопрос
это: правильно связать метод из разных классов с
Context.Wait или такой подход может привести к некоторой случайной проблеме
как тот, который мы переживаем?