/// <summary> /// Sends a proactive message to a conversation. /// </summary> /// <param name="botId">The application ID of the bot. This parameter is ignored in /// single tenant the Adapters (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> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</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 initiate a conversation with a bot /// before the bot can send activities to the user.</remarks> /// <seealso cref="RunPipelineAsync(ITurnContext, BotCallbackHandler, CancellationToken)"/> public virtual Task ContinueConversationAsync(string botId, ConversationReference reference, BotCallbackHandler callback, CancellationToken cancellationToken) { using (var context = new TurnContext(this, reference.GetContinuationActivity())) { return(RunPipelineAsync(context, callback, cancellationToken)); } }
/// <summary> /// Sends a proactive message from the bot to a conversation. /// </summary> /// <param name="botAppId">The application ID of the bot. This is the appId returned by Portal registration, and is /// generally found in the "MicrosoftAppId" parameter in appSettings.json.</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> /// <para> /// This overload differers from the Node implementation by requiring the BotId to be /// passed in. The .Net code allows multiple bots to be hosted in a single adapter which /// isn't something supported by Node. /// </para> /// </remarks> /// <seealso cref="ProcessActivity(string, Activity, Func{ITurnContext, Task})"/> /// <seealso cref="BotAdapter.RunPipeline(ITurnContext, Func{ITurnContext, Task})"/> public override 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)); } using (var context = new TurnContext(this, reference.GetContinuationActivity())) { // 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>(BotIdentityKey, claimsIdentity); var connectorClient = await CreateConnectorClientAsync(reference.ServiceUrl, claimsIdentity).ConfigureAwait(false); context.Services.Add(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, CancellationToken cancellationToken) { using (var context = new TurnContext(this, reference.GetContinuationActivity())) { return(RunPipeline(context, callback, cancellationToken)); } }
public async Task ProcessContinueConversationEvent() { var mockCredentialProvider = new Mock <ICredentialProvider>(); var mockHttpMessageHandler = new Mock <HttpMessageHandler>(); var httpClient = new HttpClient(mockHttpMessageHandler.Object); var adapter = new BotFrameworkAdapter(mockCredentialProvider.Object, customHttpClient: httpClient); ConversationReference cr = new ConversationReference { ActivityId = "activityId", Bot = new ChannelAccount { Id = "channelId", Name = "testChannelAccount", Role = "bot", }, ChannelId = "testChannel", ServiceUrl = "https://fake.service.url", Conversation = new ConversationAccount { ConversationType = string.Empty, Id = "testConversationId", IsGroup = false, Name = "testConversationName", Role = "user", }, User = new ChannelAccount { Id = "channelId", Name = "testChannelAccount", Role = "bot", }, }; var activity = cr.GetContinuationActivity(); activity.Value = "test"; // Create ClaimsIdentity that represents Skill1-to-Skill1 communication var appId = "00000000-0000-0000-0000-000000skill1"; var claims = new List <Claim> { new Claim(AuthenticationConstants.AudienceClaim, appId), new Claim(AuthenticationConstants.AppIdClaim, appId), new Claim(AuthenticationConstants.VersionClaim, "1.0") }; var identity = new ClaimsIdentity(claims); var callback = new BotCallbackHandler(async(turnContext, ct) => { var cr2 = turnContext.Activity.GetConversationReference(); cr.ActivityId = null; // activityids will be different... cr2.ActivityId = null; Assert.Equal(JsonConvert.SerializeObject(cr), JsonConvert.SerializeObject(cr2)); Assert.Equal("test", (string)turnContext.Activity.Value); }); await adapter.ProcessActivityAsync(identity, (Activity)activity, callback, default);
/// <inheritdoc/> public override Task ContinueConversationAsync(ClaimsIdentity claimsIdentity, ConversationReference reference, string audience, BotCallbackHandler callback, CancellationToken cancellationToken) { _ = claimsIdentity ?? throw new ArgumentNullException(nameof(claimsIdentity)); _ = reference ?? throw new ArgumentNullException(nameof(reference)); _ = callback ?? throw new ArgumentNullException(nameof(callback)); return(ProcessProactiveAsync(claimsIdentity, reference.GetContinuationActivity(), audience, callback, cancellationToken)); }
/// <summary> /// Sends a proactive message from the bot to a conversation. /// </summary> /// <param name="claimsIdentity">A <see cref="ClaimsIdentity"/> for the conversation.</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> /// <param name="cancellationToken">Cancellation token.</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 initialize 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><description><see cref="IIdentity"/> (key = "BotIdentity"), a claims claimsIdentity for the bot. /// </description></item> /// </list></para> /// </remarks> /// <seealso cref="BotAdapter.RunPipelineAsync(ITurnContext, BotCallbackHandler, CancellationToken)"/> public override async Task ContinueConversationAsync(ClaimsIdentity claimsIdentity, ConversationReference reference, BotCallbackHandler callback, CancellationToken cancellationToken) { using (var context = new TurnContext(this, reference.GetContinuationActivity())) { context.TurnState.Add <IIdentity>(BotIdentityKey, claimsIdentity); context.TurnState.Add <BotCallbackHandler>(callback); await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false); } }
// TODO: oauth prompt support /// <summary> /// The implementation for continue conversation. /// </summary> /// <param name="claimsIdentity">A <see cref="ClaimsIdentity"/> for the conversation.</param> /// <param name="reference">A <see cref="ConversationReference"/> for the conversation.</param> /// <param name="audience">The audience for the call.</param> /// <param name="callback">The method to call for the resulting bot turn.</param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>A task that represents the work queued to execute.</returns> protected async Task ProcessProactiveAsync(ClaimsIdentity claimsIdentity, ConversationReference reference, string audience, BotCallbackHandler callback, CancellationToken cancellationToken) { // Use the cloud environment to create the credentials for proactive requests. var credentials = await _botFrameworkAuthentication.GetProactiveCredentialsAsync(claimsIdentity, audience, cancellationToken).ConfigureAwait(false); // Create the connector client to use for outbound requests. var connectorClient = new ConnectorClient(new Uri(reference.ServiceUrl), credentials, _httpClient); // Create a turn context and run the pipeline. using (var context = CreateTurnContext(reference.GetContinuationActivity(), claimsIdentity, audience, connectorClient, callback)) { // Run the pipeline. await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false); } }
public async Task ContinueConversationAsync(ConversationReference reference, BotCallbackHandler logic, CancellationToken cancellationToken) { if (reference == null) { throw new ArgumentNullException(nameof(reference)); } if (logic == null) { throw new ArgumentNullException(nameof(logic)); } var request = reference.GetContinuationActivity().ApplyConversationReference(reference, true); using (var context = new TurnContext(this, request)) { await RunPipelineAsync(context, logic, cancellationToken).ConfigureAwait(false); } }
// TODO: oauth prompt support /// <summary> /// The implementation for continue conversation. /// </summary> /// <param name="claimsIdentity">A <see cref="ClaimsIdentity"/> for the conversation.</param> /// <param name="reference">A <see cref="ConversationReference"/> for the conversation.</param> /// <param name="audience">The audience for the call.</param> /// <param name="callback">The method to call for the resulting bot turn.</param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>A task that represents the work queued to execute.</returns> protected async Task ProcessProactiveAsync(ClaimsIdentity claimsIdentity, ConversationReference reference, string audience, BotCallbackHandler callback, CancellationToken cancellationToken) { // Use the cloud environment to create the credentials for proactive requests. var proactiveCredentialsResult = await _botFrameworkAuthentication.GetProactiveCredentialsAsync(claimsIdentity, audience, cancellationToken).ConfigureAwait(false); // Create the connector client to use for outbound requests. using (var connectorClient = new ConnectorClient(new Uri(reference.ServiceUrl), proactiveCredentialsResult.Credentials, _httpClient, disposeHttpClient: _httpClient == null)) { // Create a turn context and run the pipeline. using (var context = CreateTurnContext(reference.GetContinuationActivity(), claimsIdentity, proactiveCredentialsResult.Scope, connectorClient, callback)) { // Run the pipeline. await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false); // Cleanup disposable resources in case other code kept a reference to it. context.TurnState.Set <IConnectorClient>(null); } } }
public void ConversationReferenceGetContinuationActivity() { var locale = new CultureInfo("es-es"); var activityId = "activityId"; var user = new ChannelAccount("userId", "userName", "userRole", "userAadObjectId"); var bot = new ChannelAccount("botId", "botName", "botRole", "botAadObjectId"); var conversation = new ConversationAccount(); var channelId = "channelId"; var serviceUrl = "http://myServiceUrl.com"; var convoRef = new ConversationReference(locale, activityId, user, bot, conversation, channelId, serviceUrl); var continuationActivity = convoRef.GetContinuationActivity(); Assert.NotNull(continuationActivity); Assert.IsType <Activity>(continuationActivity); Assert.Equal(ActivityEventNames.ContinueConversation, continuationActivity.Name); Assert.Equal(channelId, continuationActivity.ChannelId); Assert.Equal(locale.ToString(), continuationActivity.Locale); Assert.Equal(serviceUrl, continuationActivity.ServiceUrl); }
/// <summary> /// Sends a proactive message to a conversation. /// </summary> /// <param name="botAppId">The application ID of the bot. This parameter is ignored in /// single tenant the Adapters (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> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</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 initiate a conversation with a bot /// before the bot can send activities to the user.</remarks> public override async Task ContinueConversationAsync(string botAppId, ConversationReference reference, BotCallbackHandler callback, CancellationToken cancellationToken) { 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)); } _logger.LogInformation($"Sending proactive message. botAppId: {botAppId}"); await ProcessActivityAsync(reference.GetContinuationActivity(), callback, cancellationToken).ConfigureAwait(false); }
public override async Task ContinueConversationAsync(string botId, ConversationReference reference, BotCallbackHandler callback, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(botId)) { throw new ArgumentNullException(nameof(botId)); } if (reference == null) { throw new ArgumentNullException(nameof(reference)); } if (callback == null) { throw new ArgumentNullException(nameof(callback)); } using (var context = new TurnContext(this, reference.GetContinuationActivity())) { await RunPipelineAsync(context, callback, cancellationToken); } }
/// <summary> /// Sends a proactive message from the bot to a conversation. /// </summary> /// <param name="botAppId">The application ID of the bot. This is the appId returned by Portal registration, and is /// generally found in the "MicrosoftAppId" parameter in appSettings.json.</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> /// <param name="cancellationToken">Cancellation token.</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> /// <para> /// This overload differers from the Node implementation by requiring the BotId to be /// passed in. The .Net code allows multiple bots to be hosted in a single adapter which /// isn't something supported by Node. /// </para> /// </remarks> /// <seealso cref="ProcessActivityAsync(string, Activity, BotCallbackHandler, CancellationToken)"/> /// <seealso cref="BotAdapter.RunPipelineAsync(ITurnContext, BotCallbackHandler, CancellationToken)"/> public override async Task ContinueConversationAsync(string botAppId, ConversationReference reference, BotCallbackHandler callback, CancellationToken cancellationToken) { 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)); } _logger.LogInformation($"Sending proactive message. botAppId: {botAppId}"); using (var context = new TurnContext(this, reference.GetContinuationActivity())) { // 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.TurnState.Add <IIdentity>(BotIdentityKey, claimsIdentity); var connectorClient = await CreateConnectorClientAsync(reference.ServiceUrl, claimsIdentity, cancellationToken).ConfigureAwait(false); context.TurnState.Add(connectorClient); await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false); } }
/// <inheritdoc/> public override Task ContinueConversationAsync(string botAppId, ConversationReference reference, BotCallbackHandler callback, CancellationToken cancellationToken) { _ = reference ?? throw new ArgumentNullException(nameof(reference)); return(ProcessProactiveAsync(CreateClaimsIdentity(botAppId), reference.GetContinuationActivity(), null, callback, cancellationToken)); }