/// <summary> /// Process an incoming message within the conversation. /// </summary> /// <remarks> /// This method: /// 1. instantiates and composes the required components /// 2. deserializes the dialog state (the dialog stack and each dialog's state) from the <see cref="toBot"/> <see cref="Message"/> /// 3. resumes the conversation processes where the dialog suspended to wait for a <see cref="Message"/> /// 4. queues <see cref="Message"/>s to be sent to the user /// 5. serializes the updated dialog state in the messages to be sent to the user. /// /// The <see cref="MakeRoot"/> factory method is invoked for new conversations only, /// because existing conversations have the dialog stack and state serialized in the <see cref="Message"/> data. /// </remarks> /// <param name="toBot">The message sent to the bot.</param> /// <param name="MakeRoot">The factory method to make the root dialog.</param> /// <param name="token">The cancellation token.</param> /// <param name="singletons">An optional list of object instances that should not be serialized.</param> /// <returns>A task that represents the message to send inline back to the user.</returns> public static async Task <Message> SendAsync(Message toBot, Func <IDialog> MakeRoot, CancellationToken token = default(CancellationToken), params object[] singletons) { IWaitFactory waits = new WaitFactory(); IFrameFactory frames = new FrameFactory(waits); IBotData botData = new JObjectBotData(toBot); IConnectorClient client = new ConnectorClient(); var botToUser = new ReactiveBotToUser(toBot, client); var provider = new Serialization.SimpleServiceLocator(singletons) { waits, frames, botData, botToUser }; var formatter = Conversation.MakeBinaryFormatter(provider); IDialogContextStore contextStore = new DialogContextStore(formatter); IDialogContextStore store = new ErrorResilientDialogContextStore(contextStore); IDialogContext context; if (!store.TryLoad(botData.PerUserInConversationData, BlobKey, out context)) { IFiberLoop fiber = new Fiber(frames); context = new Internals.DialogContext(botToUser, botData, fiber); var root = MakeRoot(); var loop = root.Loop(); context.Call <object>(loop, null); await fiber.PollAsync(); } IUserToBot userToBot = (IUserToBot)context; await userToBot.SendAsync(toBot, token); store.Save(context, botData.PerUserInConversationData, BlobKey); return(botToUser.ToUser); }
public async Task Fiber_Is_Serializable() { // arrange var waits = new WaitFactory(); var frames = new FrameFactory(waits); var fiber = new Fiber(frames); // assert var previous = fiber; AssertSerializable(ref fiber, waits, frames); Assert.IsFalse(object.ReferenceEquals(previous, fiber)); Assert.IsTrue(object.ReferenceEquals(previous.Factory, fiber.Factory)); }