diff --git a/FunctionalTests/Skills/Adaptive/AdaptiveRootBot/Middleware/LoggerMiddleware.cs b/FunctionalTests/Skills/Adaptive/AdaptiveRootBot/Middleware/LoggerMiddleware.cs index c6e2719bc..a8e0210e8 100644 --- a/FunctionalTests/Skills/Adaptive/AdaptiveRootBot/Middleware/LoggerMiddleware.cs +++ b/FunctionalTests/Skills/Adaptive/AdaptiveRootBot/Middleware/LoggerMiddleware.cs @@ -28,7 +28,7 @@ namespace Microsoft.BotBuilderSamples.AdaptiveRootBot.Middleware { // Note: skill responses will show as ContinueConversation events; we don't log those. // We only log incoming messages from users. - if (turnContext.Activity.Type != ActivityTypes.Event && turnContext.Activity.Name != "ContinueConversation") + if (!(turnContext.Activity.Type == ActivityTypes.Event && turnContext.Activity.Name == ActivityEventNames.ContinueConversation)) { var message = $"User said: {turnContext.Activity.Text} Type: \"{turnContext.Activity.Type}\" Name: \"{turnContext.Activity.Name}\""; _logger.LogInformation(message); diff --git a/FunctionalTests/Skills/DialogToDialog/DialogRootBot/Middleware/LoggerMiddleware.cs b/FunctionalTests/Skills/DialogToDialog/DialogRootBot/Middleware/LoggerMiddleware.cs index 8c0321d3b..66f5f6380 100644 --- a/FunctionalTests/Skills/DialogToDialog/DialogRootBot/Middleware/LoggerMiddleware.cs +++ b/FunctionalTests/Skills/DialogToDialog/DialogRootBot/Middleware/LoggerMiddleware.cs @@ -28,7 +28,7 @@ namespace Microsoft.BotBuilderSamples.DialogRootBot.Middleware { // Note: skill responses will show as ContinueConversation events; we don't log those. // We only log incoming messages from users. - if (turnContext.Activity.Type != ActivityTypes.Event && turnContext.Activity.Name != "ContinueConversation") + if (!(turnContext.Activity.Type == ActivityTypes.Event && turnContext.Activity.Name == ActivityEventNames.ContinueConversation)) { var message = $"User said: {turnContext.Activity.Text} Type: \"{turnContext.Activity.Type}\" Name: \"{turnContext.Activity.Name}\""; _logger.LogInformation(message); diff --git a/libraries/Microsoft.Bot.Builder/BotFrameworkAdapter.cs b/libraries/Microsoft.Bot.Builder/BotFrameworkAdapter.cs index 83301f35c..6d1a138cc 100644 --- a/libraries/Microsoft.Bot.Builder/BotFrameworkAdapter.cs +++ b/libraries/Microsoft.Bot.Builder/BotFrameworkAdapter.cs @@ -1278,7 +1278,7 @@ namespace Microsoft.Bot.Builder // Create a conversation update activity to represent the result. var eventActivity = Activity.CreateEventActivity(); - eventActivity.Name = "CreateConversation"; + eventActivity.Name = ActivityEventNames.CreateConversation; eventActivity.ChannelId = channelId; eventActivity.ServiceUrl = serviceUrl; eventActivity.Id = result.ActivityId ?? Guid.NewGuid().ToString("n"); diff --git a/libraries/Microsoft.Bot.Builder/TranscriptLoggerMiddleware.cs b/libraries/Microsoft.Bot.Builder/TranscriptLoggerMiddleware.cs index c87d5f20d..db885bcda 100644 --- a/libraries/Microsoft.Bot.Builder/TranscriptLoggerMiddleware.cs +++ b/libraries/Microsoft.Bot.Builder/TranscriptLoggerMiddleware.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Bot.Schema; @@ -17,7 +16,7 @@ namespace Microsoft.Bot.Builder /// public class TranscriptLoggerMiddleware : IMiddleware { - private static readonly JsonSerializerSettings _jsonSettings = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }; + private static readonly JsonSerializerSettings _jsonSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }; private readonly ITranscriptLogger _logger; /// @@ -41,22 +40,23 @@ namespace Microsoft.Bot.Builder /// public async Task OnTurnAsync(ITurnContext turnContext, NextDelegate nextTurn, CancellationToken cancellationToken) { - Queue transcript = new Queue(); + var transcript = new Queue(); // log incoming activity at beginning of turn if (turnContext.Activity != null) { - if (turnContext.Activity.From == null) - { - turnContext.Activity.From = new ChannelAccount(); - } + turnContext.Activity.From ??= new ChannelAccount(); if (string.IsNullOrEmpty((string)turnContext.Activity.From.Properties["role"])) { turnContext.Activity.From.Properties["role"] = "user"; } - LogActivity(transcript, CloneActivity(turnContext.Activity)); + // We should not log ContinueConversation events used by skills to initialize the middleware. + if (!(turnContext.Activity.Type == ActivityTypes.Event && turnContext.Activity.Name == ActivityEventNames.ContinueConversation)) + { + LogActivity(transcript, CloneActivity(turnContext.Activity)); + } } // hook up onSend pipeline @@ -95,12 +95,12 @@ namespace Microsoft.Bot.Builder // add MessageDelete activity // log as MessageDelete activity var deleteActivity = new Activity - { - Type = ActivityTypes.MessageDelete, - Id = reference.ActivityId, - } - .ApplyConversationReference(reference, isIncoming: false) - .AsMessageDeleteActivity(); + { + Type = ActivityTypes.MessageDelete, + Id = reference.ActivityId, + } + .ApplyConversationReference(reference, isIncoming: false) + .AsMessageDeleteActivity(); LogActivity(transcript, deleteActivity); }); @@ -163,11 +163,7 @@ namespace Microsoft.Bot.Builder private static void LogActivity(Queue transcript, IActivity activity) { - if (activity.Timestamp == null) - { - activity.Timestamp = DateTime.UtcNow; - } - + activity.Timestamp ??= DateTime.UtcNow; transcript.Enqueue(activity); } } diff --git a/libraries/Microsoft.Bot.Connector/Conversations.cs b/libraries/Microsoft.Bot.Connector/Conversations.cs index ffdc5f15e..b2c9084d8 100644 --- a/libraries/Microsoft.Bot.Connector/Conversations.cs +++ b/libraries/Microsoft.Bot.Connector/Conversations.cs @@ -275,7 +275,7 @@ namespace Microsoft.Bot.Connector Dictionary tracingParameters = new Dictionary(); tracingParameters.Add("parameters", parameters); tracingParameters.Add("cancellationToken", cancellationToken); - ServiceClientTracing.Enter(_invocationId, this, "CreateConversation", tracingParameters); + ServiceClientTracing.Enter(_invocationId, this, ActivityEventNames.CreateConversation, tracingParameters); } // Construct URL var _baseUrl = Client.BaseUri.AbsoluteUri; diff --git a/libraries/Microsoft.Bot.Schema/ActivityEventNames.cs b/libraries/Microsoft.Bot.Schema/ActivityEventNames.cs new file mode 100644 index 000000000..c60b4689c --- /dev/null +++ b/libraries/Microsoft.Bot.Schema/ActivityEventNames.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Bot.Schema +{ + /// + /// Define values for common event names used by activities of type . + /// + public static class ActivityEventNames + { + /// + /// The event name for continuing a conversation. + /// + public const string ContinueConversation = "ContinueConversation"; + + /// + /// The event name for creating a conversation. + /// + public const string CreateConversation = "CreateConversation"; + } +} diff --git a/libraries/Microsoft.Bot.Schema/ConversationReferenceEx.cs b/libraries/Microsoft.Bot.Schema/ConversationReferenceEx.cs index fd4b7d87f..b93f07dc8 100644 --- a/libraries/Microsoft.Bot.Schema/ConversationReferenceEx.cs +++ b/libraries/Microsoft.Bot.Schema/ConversationReferenceEx.cs @@ -16,17 +16,18 @@ namespace Microsoft.Bot.Schema /// Continuation activity. public Activity GetContinuationActivity() { - var activity = Activity.CreateEventActivity(); - activity.Name = "ContinueConversation"; - activity.Id = Guid.NewGuid().ToString(); - activity.ChannelId = this.ChannelId; - (activity as Activity).Locale = this.Locale; - activity.ServiceUrl = this.ServiceUrl; - activity.Conversation = this.Conversation; - activity.Recipient = this.Bot; - activity.From = this.User; - activity.RelatesTo = this; - return (Activity)activity; + return new Activity(ActivityTypes.Event) + { + Name = ActivityEventNames.ContinueConversation, + Id = Guid.NewGuid().ToString(), + ChannelId = ChannelId, + Locale = Locale, + ServiceUrl = ServiceUrl, + Conversation = Conversation, + Recipient = Bot, + From = User, + RelatesTo = this + }; } } } diff --git a/tests/Microsoft.Bot.Builder.Azure.Tests/AzureQueueTests.cs b/tests/Microsoft.Bot.Builder.Azure.Tests/AzureQueueTests.cs index 16647567f..9c31d6611 100644 --- a/tests/Microsoft.Bot.Builder.Azure.Tests/AzureQueueTests.cs +++ b/tests/Microsoft.Bot.Builder.Azure.Tests/AzureQueueTests.cs @@ -59,7 +59,7 @@ namespace Microsoft.Bot.Builder.Azure.Tests var messageJson = Encoding.UTF8.GetString(Convert.FromBase64String(message.MessageText)); var activity = JsonConvert.DeserializeObject(messageJson); Assert.Equal(ActivityTypes.Event, activity.Type); - Assert.Equal("ContinueConversation", activity.Name); + Assert.Equal(ActivityEventNames.ContinueConversation, activity.Name); Assert.Equal("foo", activity.Value); Assert.NotNull(activity.RelatesTo); var cr2 = activity.GetConversationReference(); diff --git a/tests/Microsoft.Bot.Builder.Tests/BotFrameworkAdapterTests.cs b/tests/Microsoft.Bot.Builder.Tests/BotFrameworkAdapterTests.cs index d16f73168..52cd79524 100644 --- a/tests/Microsoft.Bot.Builder.Tests/BotFrameworkAdapterTests.cs +++ b/tests/Microsoft.Bot.Builder.Tests/BotFrameworkAdapterTests.cs @@ -64,7 +64,7 @@ namespace Microsoft.Bot.Builder.Tests const string conversationIdName = "Id"; const string conversationIdValue = "NewConversationId"; const string tenantIdValue = "theTenantId"; - const string eventActivityName = "CreateConversation"; + const string eventActivityName = ActivityEventNames.CreateConversation; Task CreateResponseMessage() { diff --git a/tests/Microsoft.Bot.Builder.Tests/TranscriptLoggerMiddlewareTests.cs b/tests/Microsoft.Bot.Builder.Tests/TranscriptLoggerMiddlewareTests.cs new file mode 100644 index 000000000..c932d30dd --- /dev/null +++ b/tests/Microsoft.Bot.Builder.Tests/TranscriptLoggerMiddlewareTests.cs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Threading.Tasks; +using Microsoft.Bot.Builder.Adapters; +using Microsoft.Bot.Schema; +using Xunit; + +namespace Microsoft.Bot.Builder.Tests +{ + public class TranscriptLoggerMiddlewareTests + { + [Fact] + public async Task ShouldNotLogContinueConversation() + { + var transcriptStore = new MemoryTranscriptStore(); + var sut = new TranscriptLoggerMiddleware(transcriptStore); + + var conversationId = Guid.NewGuid().ToString(); + var adapter = new TestAdapter(TestAdapter.CreateConversation(conversationId)) + .Use(sut); + + await new TestFlow(adapter, async (context, cancellationToken) => + { + await context.SendActivityAsync("bar", cancellationToken: cancellationToken); + }) + .Send("foo") + .AssertReply(async activity => + { + Assert.Equal("bar", ((Activity)activity).Text); + var activities = await transcriptStore.GetTranscriptActivitiesAsync(activity.ChannelId, conversationId); + Assert.Equal(2, activities.Items.Length); + }) + .Send(new Activity(ActivityTypes.Event) { Name = ActivityEventNames.ContinueConversation }) + .AssertReply(async activity => + { + // Ensure the event hasn't been added to the transcript. + var activities = await transcriptStore.GetTranscriptActivitiesAsync(activity.ChannelId, conversationId); + Assert.DoesNotContain(activities.Items, a => ((Activity)a).Type == ActivityTypes.Event && ((Activity)a).Name == ActivityEventNames.ContinueConversation); + Assert.Equal(3, activities.Items.Length); + }) + .StartTestAsync(); + } + } +}