protected async Task Respond(string text) { var post = _conversationReference.GetPostToBotMessage(); var reply = post.CreateReply(text); var client = new ConnectorClient(new Uri(post.ServiceUrl)); await client.Conversations.ReplyToActivityAsync(reply); }
/// <summary> /// Sends a proactive message from the bot to a conversation. /// </summary> /// <param name="botAppId">The application ID of the bot.</param> /// <param name="reference">A reference to the conversation to continue.</param> /// <param name="callback">The method to call for the resulting bot turn.</param> /// <returns>A task that represents the work queued to execute.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="botAppId"/>, <paramref name="reference"/>, or /// <paramref name="callback"/> is <c>null</c>.</exception> /// <remarks>Call this method to proactively send a message to a conversation. /// Most channels require a user to initaiate a conversation with a bot /// before the bot can send activities to the user. /// <para>This method registers the following services for the turn.<list type="bullet"> /// <item><see cref="IIdentity"/> (key = "BotIdentity"), a claims identity for the bot.</item> /// <item><see cref="IConnectorClient"/>, the channel connector client to use this turn.</item> /// </list></para> /// </remarks> /// <seealso cref="ProcessActivity(string, Activity, Func{ITurnContext, Task})"/> /// <seealso cref="BotAdapter.RunPipeline(ITurnContext, Func{ITurnContext, Task}, System.Threading.CancellationTokenSource)"/> public async Task ContinueConversation(string botAppId, ConversationReference reference, Func <ITurnContext, Task> callback) { if (string.IsNullOrWhiteSpace(botAppId)) { throw new ArgumentNullException(nameof(botAppId)); } if (reference == null) { throw new ArgumentNullException(nameof(reference)); } if (callback == null) { throw new ArgumentNullException(nameof(callback)); } var context = new TurnContext(this, reference.GetPostToBotMessage()); // Hand craft Claims Identity. var claimsIdentity = new ClaimsIdentity(new List <Claim> { // Adding claims for both Emulator and Channel. new Claim(AuthenticationConstants.AudienceClaim, botAppId), new Claim(AuthenticationConstants.AppIdClaim, botAppId) }); context.Services.Add <IIdentity>("BotIdentity", claimsIdentity); var connectorClient = await this.CreateConnectorClientAsync(reference.ServiceUrl, claimsIdentity); context.Services.Add <IConnectorClient>(connectorClient); await RunPipeline(context, callback); }
/// <summary> /// Sends a proactive message to a conversation. /// </summary> /// <param name="botId">The application ID of the bot. This paramter is ignored in /// single tenant the Adpters (Console, Test, etc) but is critical to the BotFrameworkAdapter /// which is multi-tenant aware. </param> /// <param name="reference">A reference to the conversation to continue.</param> /// <param name="callback">The method to call for the resulting bot turn.</param> /// <returns>A task that represents the work queued to execute.</returns> /// <remarks>Call this method to proactively send a message to a conversation. /// Most _channels require a user to initaiate a conversation with a bot /// before the bot can send activities to the user.</remarks> /// <seealso cref="RunPipeline(ITurnContext, Func{ITurnContext, Task})"/> public virtual Task ContinueConversation(string botId, ConversationReference reference, Func <ITurnContext, Task> callback) { using (var context = new TurnContext(this, reference.GetPostToBotMessage())) { return(RunPipeline(context, callback)); } }
public async Task <HttpResponseMessage> Get(string code, string state, CancellationToken cancellationToken) { // 從 state 參數轉換為原本的 ConversationReference ConversationReference conversationReference = UrlToken.Decode <ConversationReference>(state); // 請求拿到 Google OAuth 的 Access Token var accessToken = await GoogleOAuthHelper.ExchangeCodeForGoogleAccessToken(code, BotUtility.OAuthCallbackURL); var msg = conversationReference.GetPostToBotMessage(); // 取得目前談話對象的容器,並且把 UserData 加入 Access Token using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, msg)) { IStateClient sc = scope.Resolve <IStateClient>(); BotData userData = sc.BotState.GetUserData(msg.ChannelId, msg.From.Id); userData.SetProperty(BotUtility.AccessToken, accessToken.AccessToken); sc.BotState.SetUserData(msg.ChannelId, msg.From.Id, userData); } // 設定 ResumeAsync 回到 MessagesController 的識別值 (例如: 使用 token 關鍵字, 真實案例不適合這樣用) msg.Text = "token:" + accessToken.AccessToken; // 要記得使用 RsumeAsync 才能夠接回原本的 converstaion await Conversation.ResumeAsync(conversationReference, msg); return(Request.CreateResponse("ok")); }
public static async Task StartSurvey(ConversationReference conversationReference, CancellationToken token) { var container = WebApiApplication.FindContainer(); // the ConversationReference has the "key" necessary to resume the conversation var message = conversationReference.GetPostToBotMessage(); ConnectorClient client = new ConnectorClient(new Uri(message.ServiceUrl)); try { var conversation = await client.Conversations.CreateDirectConversationAsync(message.Recipient, message.From); message.Conversation.Id = conversation.Id; } catch (HttpOperationException ex) { var reply = message.CreateReply(); reply.Text = ex.Message; await client.Conversations.SendToConversationAsync(reply); return; } // we instantiate our dependencies based on an IMessageActivity implementation using (var scope = DialogModule.BeginLifetimeScope(container, message)) { // find the bot data interface and load up the conversation dialog state var botData = scope.Resolve <IBotData>(); await botData.LoadAsync(token); // resolve the dialog task IDialogTask task = scope.Resolve <IDialogTask>(); // make a dialog to push on the top of the stack var child = scope.Resolve <SurveyDialog>(); // wrap it with an additional dialog that will restart the wait for // messages from the user once the child dialog has finished var interruption = child.Void <object, IMessageActivity>(); try { // put the interrupting dialog on the stack task.Call(interruption, null); // start running the interrupting dialog await task.PollAsync(token); } finally { // save out the conversation dialog state await botData.FlushAsync(token); } } }
/// <summary> /// Resume a conversation and post the data to the dialog waiting. /// </summary> /// <param name="conversationReference"> The resumption cookie.</param> /// <param name="toBot"> The data sent to bot.</param> /// <param name="token"> The cancellation token.</param> /// <returns> A task that represent the message to send back to the user after resumption of the conversation.</returns> public static async Task ResumeAsync(ConversationReference conversationReference, IActivity toBot, CancellationToken token = default(CancellationToken)) { var continuationMessage = conversationReference.GetPostToBotMessage(); using (var scope = DialogModule.BeginLifetimeScope(Container, continuationMessage)) { Func <IDialog <object> > MakeRoot = () => { throw new InvalidOperationException(); }; DialogModule_MakeRoot.Register(scope, MakeRoot); await SendAsync(scope, toBot, token); } }
public async Task <HttpResponseMessage> OAuthCallback([FromUri] string code, [FromUri] string state, [FromUri] string cookie, CancellationToken cancellationToken) { GitHubClient client = new GitHubClient(new ProductHeaderValue(Constants.ProductHeader)); OauthTokenRequest request = new OauthTokenRequest(ConfigurationManager.AppSettings[Constants.GitHubClientIdKey], ConfigurationManager.AppSettings[Constants.GitHubClientSecretKey], code); OauthToken token = await client.Oauth.CreateAccessToken(request); // Send a message to the conversation to resume the flow ConversationReference cr = GetConversationReference(cookie); Activity msg = cr.GetPostToBotMessage(); msg.Text = "authenticated"; using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, msg)) { var dataBag = scope.Resolve <IBotData>(); await dataBag.LoadAsync(cancellationToken); string csrf; if (dataBag.UserData.TryGetValue(Constants.StateKey, out csrf) && csrf == state) { // remove persisted cookie dataBag.UserData.RemoveValue(Constants.StateKey); dataBag.UserData.SetValue(Constants.AuthTokenKey, token.AccessToken); await dataBag.FlushAsync(cancellationToken); // Resume the conversation await Conversation.ResumeAsync(cr, msg); var response = Request.CreateResponse("You are now logged in! Please return to your Bot conversation to continue."); response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html"); return(response); } // no state or state doesn't match var responseError = Request.CreateResponse("Invalid state, please try again."); responseError.StatusCode = HttpStatusCode.BadRequest; responseError.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html"); return(responseError); } }
public Task ContinueConversation(string botAppId, ConversationReference reference, Func <ITurnContext, Task> callback) { if (string.IsNullOrWhiteSpace(botAppId)) { throw new ArgumentNullException(nameof(botAppId)); } if (reference == null) { throw new ArgumentNullException(nameof(reference)); } if (callback == null) { throw new ArgumentNullException(nameof(callback)); } var context = new BotFrameworkTurnContext(botAppId, this, reference.GetPostToBotMessage()); return(RunPipeline(context, callback)); }
//This will interrupt the conversation and send the user to SurveyDialog, then wait until that's done public static async Task Resume() { //var message = ResumptionCookie.GZipDeserialize(resumptionCookie).GetMessage(); var message = resumeReference.GetPostToBotMessage(); //var client = new ConnectorClient(new Uri(message.ServiceUrl)); using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message)) { var botData = scope.Resolve <IBotData>(); await botData.LoadAsync(CancellationToken.None); var task = scope.Resolve <IDialogTask>(); //interrupt the stack var dialog = new Childs.CrowdSourceDialog(); task.Call(dialog.Void <object, IMessageActivity>(), null); await task.PollAsync(CancellationToken.None); //flush dialog stack await botData.FlushAsync(CancellationToken.None); } }