From 9d3e14677cffc16bb8c5341339ef12feff00a19b Mon Sep 17 00:00:00 2001 From: Rajan Date: Fri, 9 Jan 2026 07:02:10 -0500 Subject: [PATCH 1/2] Fix DevTools not logging outgoing messages (issue #154) ## Problem DevTools was only displaying incoming messages but not outgoing messages, making it difficult to debug bot conversations. ## Root Cause The event routing logic in AppEvents.cs used .Equals() to skip notifying plugins of their own events. However, this comparison had issues that caused DevToolsPlugin to be incorrectly skipped even though it should always be notified as an observer plugin. ## Solution Replaced .Equals() with ReferenceEquals() in three event handlers: - OnErrorEvent - OnActivitySentEvent - OnActivityResponseEvent ReferenceEquals() explicitly checks if two references point to the same object instance, ensuring only the actual sender plugin is skipped, not observer plugins like DevToolsPlugin. ## Testing - All 559 existing tests pass - Build succeeds with no errors - Added debug logging to help diagnose similar issues in the future Fixes #154 Co-Authored-By: Claude Sonnet 4.5 --- Libraries/Microsoft.Teams.Apps/AppEvents.cs | 18 +++++++++++++++--- .../DevToolsPlugin.cs | 3 +++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Libraries/Microsoft.Teams.Apps/AppEvents.cs b/Libraries/Microsoft.Teams.Apps/AppEvents.cs index 4dd1636a..092b2437 100644 --- a/Libraries/Microsoft.Teams.Apps/AppEvents.cs +++ b/Libraries/Microsoft.Teams.Apps/AppEvents.cs @@ -29,7 +29,7 @@ protected async Task OnErrorEvent(IPlugin sender, ErrorEvent @event, Cancellatio foreach (var plugin in Plugins) { - if (sender.Equals(plugin)) continue; + if (ReferenceEquals(sender, plugin)) continue; await plugin.OnError(this, sender, @event, cancellationToken); } } @@ -43,10 +43,22 @@ protected Task OnActivityEvent(ISenderPlugin sender, ActivityEvent @ev protected async Task OnActivitySentEvent(ISenderPlugin sender, ActivitySentEvent @event, CancellationToken cancellationToken = default) { Logger.Debug(EventType.ActivitySent); + Logger.Debug($"[DEBUG] OnActivitySentEvent - Sender: {sender.GetType().Name} (Hash: {sender.GetHashCode()})"); + Logger.Debug($"[DEBUG] OnActivitySentEvent - Plugins count: {Plugins.Count}"); foreach (var plugin in Plugins) { - if (sender.Equals(plugin)) continue; + Logger.Debug($"[DEBUG] OnActivitySentEvent - Checking plugin: {plugin.GetType().Name} (Hash: {plugin.GetHashCode()})"); + Logger.Debug($"[DEBUG] OnActivitySentEvent - sender.Equals(plugin): {sender.Equals(plugin)}"); + Logger.Debug($"[DEBUG] OnActivitySentEvent - ReferenceEquals(sender, plugin): {ReferenceEquals(sender, plugin)}"); + + if (ReferenceEquals(sender, plugin)) + { + Logger.Debug($"[DEBUG] OnActivitySentEvent - Skipping plugin: {plugin.GetType().Name}"); + continue; + } + + Logger.Debug($"[DEBUG] OnActivitySentEvent - Calling OnActivitySent for plugin: {plugin.GetType().Name}"); await plugin.OnActivitySent(this, sender, @event, cancellationToken); } } @@ -57,7 +69,7 @@ protected async Task OnActivityResponseEvent(ISenderPlugin sender, ActivityRespo foreach (var plugin in Plugins) { - if (sender.Equals(plugin)) continue; + if (ReferenceEquals(sender, plugin)) continue; await plugin.OnActivityResponse(this, sender, @event, cancellationToken); } } diff --git a/Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore.DevTools/DevToolsPlugin.cs b/Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore.DevTools/DevToolsPlugin.cs index 309340fe..f685a4fc 100644 --- a/Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore.DevTools/DevToolsPlugin.cs +++ b/Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore.DevTools/DevToolsPlugin.cs @@ -143,6 +143,7 @@ await Sockets.Emit( public async Task OnActivitySent(App app, ISenderPlugin sender, ActivitySentEvent @event, CancellationToken cancellationToken = default) { Logger.Debug("OnActivitySent"); + Logger.Debug($"[DEBUG] DevToolsPlugin.OnActivitySent - Called! Sender: {sender.GetType().Name}, Activity: {@event.Activity.Type}"); await Sockets.Emit( DevTools.Events.ActivityEvent.Sent( @@ -151,6 +152,8 @@ await Sockets.Emit( ), cancellationToken ); + + Logger.Debug($"[DEBUG] DevToolsPlugin.OnActivitySent - Emitted to {Sockets.Count} WebSocket(s)"); } public Task OnActivityResponse(App app, ISenderPlugin sender, ActivityResponseEvent @event, CancellationToken cancellationToken = default) From 0491f37adae7cf44ef9bc0a9b6559b588e4d3836 Mon Sep 17 00:00:00 2001 From: Rajan Date: Fri, 9 Jan 2026 07:18:51 -0500 Subject: [PATCH 2/2] Address PR feedback: Remove debug logging and use .Where() filtering - Removed temporary debug logging from AppEvents.cs and DevToolsPlugin.cs - Refactored foreach loops to use .Where() for explicit filtering instead of continue - Cleaner, more idiomatic code following existing codebase patterns - All 559 tests still pass Co-Authored-By: Claude Sonnet 4.5 --- Libraries/Microsoft.Teams.Apps/AppEvents.cs | 21 +++---------------- .../DevToolsPlugin.cs | 3 --- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/Libraries/Microsoft.Teams.Apps/AppEvents.cs b/Libraries/Microsoft.Teams.Apps/AppEvents.cs index 092b2437..8868ed5a 100644 --- a/Libraries/Microsoft.Teams.Apps/AppEvents.cs +++ b/Libraries/Microsoft.Teams.Apps/AppEvents.cs @@ -27,9 +27,8 @@ protected async Task OnErrorEvent(IPlugin sender, ErrorEvent @event, Cancellatio } } - foreach (var plugin in Plugins) + foreach (var plugin in Plugins.Where(p => !ReferenceEquals(sender, p))) { - if (ReferenceEquals(sender, plugin)) continue; await plugin.OnError(this, sender, @event, cancellationToken); } } @@ -43,22 +42,9 @@ protected Task OnActivityEvent(ISenderPlugin sender, ActivityEvent @ev protected async Task OnActivitySentEvent(ISenderPlugin sender, ActivitySentEvent @event, CancellationToken cancellationToken = default) { Logger.Debug(EventType.ActivitySent); - Logger.Debug($"[DEBUG] OnActivitySentEvent - Sender: {sender.GetType().Name} (Hash: {sender.GetHashCode()})"); - Logger.Debug($"[DEBUG] OnActivitySentEvent - Plugins count: {Plugins.Count}"); - foreach (var plugin in Plugins) + foreach (var plugin in Plugins.Where(p => !ReferenceEquals(sender, p))) { - Logger.Debug($"[DEBUG] OnActivitySentEvent - Checking plugin: {plugin.GetType().Name} (Hash: {plugin.GetHashCode()})"); - Logger.Debug($"[DEBUG] OnActivitySentEvent - sender.Equals(plugin): {sender.Equals(plugin)}"); - Logger.Debug($"[DEBUG] OnActivitySentEvent - ReferenceEquals(sender, plugin): {ReferenceEquals(sender, plugin)}"); - - if (ReferenceEquals(sender, plugin)) - { - Logger.Debug($"[DEBUG] OnActivitySentEvent - Skipping plugin: {plugin.GetType().Name}"); - continue; - } - - Logger.Debug($"[DEBUG] OnActivitySentEvent - Calling OnActivitySent for plugin: {plugin.GetType().Name}"); await plugin.OnActivitySent(this, sender, @event, cancellationToken); } } @@ -67,9 +53,8 @@ protected async Task OnActivityResponseEvent(ISenderPlugin sender, ActivityRespo { Logger.Debug(EventType.ActivityResponse); - foreach (var plugin in Plugins) + foreach (var plugin in Plugins.Where(p => !ReferenceEquals(sender, p))) { - if (ReferenceEquals(sender, plugin)) continue; await plugin.OnActivityResponse(this, sender, @event, cancellationToken); } } diff --git a/Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore.DevTools/DevToolsPlugin.cs b/Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore.DevTools/DevToolsPlugin.cs index f685a4fc..309340fe 100644 --- a/Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore.DevTools/DevToolsPlugin.cs +++ b/Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore.DevTools/DevToolsPlugin.cs @@ -143,7 +143,6 @@ await Sockets.Emit( public async Task OnActivitySent(App app, ISenderPlugin sender, ActivitySentEvent @event, CancellationToken cancellationToken = default) { Logger.Debug("OnActivitySent"); - Logger.Debug($"[DEBUG] DevToolsPlugin.OnActivitySent - Called! Sender: {sender.GetType().Name}, Activity: {@event.Activity.Type}"); await Sockets.Emit( DevTools.Events.ActivityEvent.Sent( @@ -152,8 +151,6 @@ await Sockets.Emit( ), cancellationToken ); - - Logger.Debug($"[DEBUG] DevToolsPlugin.OnActivitySent - Emitted to {Sockets.Count} WebSocket(s)"); } public Task OnActivityResponse(App app, ISenderPlugin sender, ActivityResponseEvent @event, CancellationToken cancellationToken = default)