From 68aa4a135e65a1ef887a4b3a9c850530112a6573 Mon Sep 17 00:00:00 2001
From: "Jeremy D. Miller" <jeremydmiller@yahoo.com>
Date: Tue, 21 Nov 2023 07:31:59 -0600
Subject: [PATCH] Add routing diagnostics to diagnostics doc page  Closes
 GH-324

---
 docs/guide/diagnostics.md                     | 33 +++++++++++++++++++
 docs/guide/durability/efcore.md               |  8 ++---
 docs/guide/durability/managing.md             |  4 +--
 docs/guide/durability/sqlserver.md            |  2 +-
 docs/tutorials/best-practices.md              |  2 +-
 .../Runtime/Routing/routing_precedence.cs     | 17 ++++++++++
 6 files changed, 58 insertions(+), 8 deletions(-)

diff --git a/docs/guide/diagnostics.md b/docs/guide/diagnostics.md
index 4ed969950..706d88985 100644
--- a/docs/guide/diagnostics.md
+++ b/docs/guide/diagnostics.md
@@ -150,3 +150,36 @@ public static void assert_configuration_is_valid(IHost host)
 Note that this method will attempt to generate and compile the source code for each message type and use [Lamar's own
 diagnostics](https://jasperfx.github.io/lamar/guide/ioc/diagnostics/) as well.
 
+## Troubleshooting Message Routing
+
+Among other information, you can find a preview of how Wolverine will route known message types through the command line
+with:
+
+```bash
+dotnet run -- describe
+```
+
+Part of this output is a table of the known message types and the routed destination of any subscriptions. You can enhance
+this diagnostic by helping Wolverine to [discover message types](/guide/messages#message-discovery) in your system. 
+
+And lastly, there's a programmatic way to "preview" the Wolverine message routing at runtime that might 
+be helpful:
+
+<!-- snippet: sample_using_preview_subscriptions -->
+<a id='snippet-sample_using_preview_subscriptions'></a>
+```cs
+public static void using_preview_subscriptions(IMessageBus bus)
+{
+    // Preview where Wolverine is wanting to send a message
+    var outgoing = bus.PreviewSubscriptions(new BlueMessage());
+    foreach (var envelope in outgoing)
+    {
+        // The URI value here will identify the endpoint where the message is
+        // going to be sent (Rabbit MQ exchange, Azure Service Bus topic, Kafka topic, local queue, etc.)
+        Debug.WriteLine(envelope.Destination);
+    }
+}
+```
+<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Testing/CoreTests/Runtime/Routing/routing_precedence.cs#L76-L90' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_preview_subscriptions' title='Start of snippet'>anchor</a></sup>
+<!-- endSnippet -->
+
diff --git a/docs/guide/durability/efcore.md b/docs/guide/durability/efcore.md
index 1a659ee95..547470966 100644
--- a/docs/guide/durability/efcore.md
+++ b/docs/guide/durability/efcore.md
@@ -31,7 +31,7 @@ builder.Host.UseWolverine(opts =>
     opts.Policies.UseDurableLocalQueues();
 });
 ```
-<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Samples/EFCoreSample/ItemService/Program.cs#L35-L52' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_registering_efcore_middleware' title='Start of snippet'>anchor</a></sup>
+<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Samples/EFCoreSample/ItemService/Program.cs#L36-L53' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_registering_efcore_middleware' title='Start of snippet'>anchor</a></sup>
 <!-- endSnippet -->
 
 ::: tip
@@ -124,7 +124,7 @@ this syntax for the service registration:
 builder.Services.AddDbContextWithWolverineIntegration<ItemsDbContext>(
     x => x.UseSqlServer(connectionString), "wolverine");
 ```
-<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Samples/EFCoreSample/ItemService/Program.cs#L18-L25' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_optimized_efcore_registration' title='Start of snippet'>anchor</a></sup>
+<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Samples/EFCoreSample/ItemService/Program.cs#L19-L26' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_optimized_efcore_registration' title='Start of snippet'>anchor</a></sup>
 <!-- endSnippet -->
 
 That registration will:
@@ -219,7 +219,7 @@ public async Task Post(
     await outbox.SaveChangesAndFlushMessagesAsync();
 }
 ```
-<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Samples/EFCoreSample/ItemService/CreateItemController.cs#L8-L38' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_dbcontext_outbox_1' title='Start of snippet'>anchor</a></sup>
+<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Samples/EFCoreSample/ItemService/CreateItemController.cs#L10-L40' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_dbcontext_outbox_1' title='Start of snippet'>anchor</a></sup>
 <!-- endSnippet -->
 
 Or use the `IDbContextOutbox` as shown below, but in this case you will need to explicitly call `Enroll()` on
@@ -261,7 +261,7 @@ public async Task Post3(
     await outbox.SaveChangesAndFlushMessagesAsync();
 }
 ```
-<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Samples/EFCoreSample/ItemService/CreateItemController.cs#L41-L76' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_dbcontext_outbox_2' title='Start of snippet'>anchor</a></sup>
+<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Samples/EFCoreSample/ItemService/CreateItemController.cs#L43-L78' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_dbcontext_outbox_2' title='Start of snippet'>anchor</a></sup>
 <!-- endSnippet -->
 
 ## As Saga Storage
diff --git a/docs/guide/durability/managing.md b/docs/guide/durability/managing.md
index 6d1596080..bdbb1102b 100644
--- a/docs/guide/durability/managing.md
+++ b/docs/guide/durability/managing.md
@@ -75,7 +75,7 @@ To have any missing database schema objects built as needed on application start
 // This is rebuilding the persistent storage database schema on startup
 builder.Host.UseResourceSetupOnStartup();
 ```
-<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Samples/EFCoreSample/ItemService/Program.cs#L54-L59' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_resource_setup_on_startup' title='Start of snippet'>anchor</a></sup>
+<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Samples/EFCoreSample/ItemService/Program.cs#L55-L60' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_resource_setup_on_startup' title='Start of snippet'>anchor</a></sup>
 <!-- endSnippet -->
 
 ## Command Line Management
@@ -89,7 +89,7 @@ shown in this last line of a .NET 6/7 `Program` code file:
 // Opt into using Oakton for command parsing
 await app.RunOaktonCommands(args);
 ```
-<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Samples/EFCoreSample/ItemService/Program.cs#L80-L85' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_oakton_for_command_line_parsing' title='Start of snippet'>anchor</a></sup>
+<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Samples/EFCoreSample/ItemService/Program.cs#L83-L88' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_oakton_for_command_line_parsing' title='Start of snippet'>anchor</a></sup>
 <!-- endSnippet -->
 
 And you're using the message persistence from either the `WolverineFx.SqlServer` or `WolverineFx.Postgresql`
diff --git a/docs/guide/durability/sqlserver.md b/docs/guide/durability/sqlserver.md
index d7f2b907b..105051a78 100644
--- a/docs/guide/durability/sqlserver.md
+++ b/docs/guide/durability/sqlserver.md
@@ -30,7 +30,7 @@ builder.Host.UseWolverine(opts =>
     opts.Policies.UseDurableLocalQueues();
 });
 ```
-<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Samples/EFCoreSample/ItemService/Program.cs#L35-L52' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_registering_efcore_middleware' title='Start of snippet'>anchor</a></sup>
+<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Samples/EFCoreSample/ItemService/Program.cs#L36-L53' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_registering_efcore_middleware' title='Start of snippet'>anchor</a></sup>
 <!-- endSnippet -->
 
 ## Sql Server Messaging Transport
diff --git a/docs/tutorials/best-practices.md b/docs/tutorials/best-practices.md
index 3881c2a68..a9cde4510 100644
--- a/docs/tutorials/best-practices.md
+++ b/docs/tutorials/best-practices.md
@@ -224,4 +224,4 @@ has quite a bit of features specifically to support a "Vertical Slice Architectu
 to utilize Wolverine to create a maintainable codebase with much less complexity than the state of the art Clean/Onion
 layered approach.
 
-See [Low Ceremony Vertical Slice Architecture with Wolverine](https://jeremydmiller.com/2023/07/10/low-ceremony-vertical-slice-architecture-with-wolverine/)
\ No newline at end of file
+See [Low Ceremony Vertical Slice Architecture with Wolverine](https://jeremydmiller.com/2023/07/10/low-ceremony-vertical-slice-architecture-with-wolverine/)
diff --git a/src/Testing/CoreTests/Runtime/Routing/routing_precedence.cs b/src/Testing/CoreTests/Runtime/Routing/routing_precedence.cs
index fb236556f..42ea5b994 100644
--- a/src/Testing/CoreTests/Runtime/Routing/routing_precedence.cs
+++ b/src/Testing/CoreTests/Runtime/Routing/routing_precedence.cs
@@ -1,6 +1,7 @@
 using System;
 using System.CodeDom.Compiler;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Linq;
 using System.Threading.Tasks;
 using Microsoft.Extensions.DependencyInjection;
@@ -71,6 +72,22 @@ public async Task explicit_routing_to_local_wins()
         bus.PreviewSubscriptions(new BlueMessage())
             .Single().Destination.ShouldBe(new Uri("local://purple"));
     }
+
+    #region sample_using_preview_subscriptions
+
+    public static void using_preview_subscriptions(IMessageBus bus)
+    {
+        // Preview where Wolverine is wanting to send a message
+        var outgoing = bus.PreviewSubscriptions(new BlueMessage());
+        foreach (var envelope in outgoing)
+        {
+            // The URI value here will identify the endpoint where the message is
+            // going to be sent (Rabbit MQ exchange, Azure Service Bus topic, Kafka topic, local queue, etc.)
+            Debug.WriteLine(envelope.Destination);
+        }
+    }
+
+    #endregion
     
     [Fact]
     public async Task explicit_routing_to_elsewhere_wins()