diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index bb6efbd1e1..9494512cec 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -28,7 +28,7 @@
-
+
@@ -41,7 +41,7 @@
-
+
diff --git a/src/ServiceControl.Transports.ASBS.Tests/ServiceControl.Transports.ASBS.Tests.csproj b/src/ServiceControl.Transports.ASBS.Tests/ServiceControl.Transports.ASBS.Tests.csproj
index 58b234a7e1..eb5e30a4ce 100644
--- a/src/ServiceControl.Transports.ASBS.Tests/ServiceControl.Transports.ASBS.Tests.csproj
+++ b/src/ServiceControl.Transports.ASBS.Tests/ServiceControl.Transports.ASBS.Tests.csproj
@@ -5,6 +5,7 @@
+
diff --git a/src/ServiceControl.Transports.ASBS/ASBSTransportCustomization.cs b/src/ServiceControl.Transports.ASBS/ASBSTransportCustomization.cs
index 7b84f142f5..5a600a385f 100644
--- a/src/ServiceControl.Transports.ASBS/ASBSTransportCustomization.cs
+++ b/src/ServiceControl.Transports.ASBS/ASBSTransportCustomization.cs
@@ -1,9 +1,12 @@
namespace ServiceControl.Transports.ASBS
{
using System.Linq;
+ using System.Text.Json;
using BrokerThroughput;
+ using Configuration;
using Microsoft.Extensions.DependencyInjection;
using NServiceBus;
+ using NServiceBus.Transport.AzureServiceBus;
public class ASBSTransportCustomization : TransportCustomization
{
@@ -19,18 +22,27 @@ protected override void CustomizeTransportForMonitoringEndpoint(EndpointConfigur
protected override AzureServiceBusTransport CreateTransport(TransportSettings transportSettings, TransportTransactionMode preferredTransactionMode = TransportTransactionMode.ReceiveOnly)
{
var connectionSettings = ConnectionStringParser.Parse(transportSettings.ConnectionString);
- var transport = connectionSettings.AuthenticationMethod.CreateTransportDefinition(connectionSettings);
- transport.UseWebSockets = connectionSettings.UseWebSockets;
- if (connectionSettings.TopicName != null)
+ if (!transportSettings.TryGet(out TopicTopology selectedTopology))
{
- transport.Topology = TopicTopology.Single(connectionSettings.TopicName);
+ //Topology is pre-selected and customized only when creating transport for the primary instance
+ //For all other cases use the connection string to determine which topology to use
+ if (connectionSettings.TopicName != null)
+ {
+#pragma warning disable CS0618 // Type or member is obsolete
+ selectedTopology = TopicTopology.MigrateFromNamedSingleTopic(connectionSettings.TopicName);
+#pragma warning restore CS0618 // Type or member is obsolete
+ }
+ else
+ {
+ selectedTopology = TopicTopology.Default;
+ }
}
+ var transport = connectionSettings.AuthenticationMethod.CreateTransportDefinition(connectionSettings, selectedTopology);
+ transport.UseWebSockets = connectionSettings.UseWebSockets;
transport.EnablePartitioning = connectionSettings.EnablePartitioning;
- transport.ConfigureNameShorteners();
-
transport.TransportTransactionMode = transport.GetSupportedTransactionModes().Contains(preferredTransactionMode) ? preferredTransactionMode : TransportTransactionMode.ReceiveOnly;
return transport;
@@ -40,6 +52,46 @@ protected override void AddTransportForPrimaryCore(IServiceCollection services,
TransportSettings transportSettings)
{
services.AddSingleton();
+
+ var connectionSettings = ConnectionStringParser.Parse(transportSettings.ConnectionString);
+ TopicTopology selectedTopology;
+
+ var serviceBusRootNamespace = new SettingsRootNamespace("ServiceControl.Transport.ASBS");
+ if (connectionSettings.TopicName != null)
+ {
+ //Bundle name provided -> use migration topology
+ //Need to explicitly specific events to be published on the single topic
+#pragma warning disable CS0618 // Type or member is obsolete
+ selectedTopology = TopicTopology.FromOptions(new MigrationTopologyOptions
+#pragma warning restore CS0618 // Type or member is obsolete
+ {
+ TopicToPublishTo = connectionSettings.TopicName,
+ TopicToSubscribeOn = connectionSettings.TopicName,
+ EventsToMigrateMap = [
+ "ServiceControl.Contracts.CustomCheckFailed",
+ "ServiceControl.Contracts.CustomCheckSucceeded",
+ "ServiceControl.Contracts.HeartbeatRestored",
+ "ServiceControl.Contracts.HeartbeatStopped",
+ "ServiceControl.Contracts.FailedMessagesArchived",
+ "ServiceControl.Contracts.FailedMessagesUnArchived",
+ "ServiceControl.Contracts.MessageFailed",
+ "ServiceControl.Contracts.MessageFailureResolvedByRetry",
+ "ServiceControl.Contracts.MessageFailureResolvedManually"
+ ]
+ });
+ }
+ else if (SettingsReader.TryRead(serviceBusRootNamespace, "Topology", out var topologyJson))
+ {
+ //Load topology from json
+ selectedTopology = TopicTopology.FromOptions(JsonSerializer.Deserialize(topologyJson, TopologyOptionsSerializationContext.Default.TopologyOptions));
+ }
+ else
+ {
+ //Default to topic-per-event topology
+ selectedTopology = TopicTopology.Default;
+ }
+
+ transportSettings.Set(selectedTopology);
}
protected override void AddTransportForMonitoringCore(IServiceCollection services, TransportSettings transportSettings)
diff --git a/src/ServiceControl.Transports.ASBS/AuthenticationMethod.cs b/src/ServiceControl.Transports.ASBS/AuthenticationMethod.cs
index a9f61fc1e3..966b2f3c3d 100644
--- a/src/ServiceControl.Transports.ASBS/AuthenticationMethod.cs
+++ b/src/ServiceControl.Transports.ASBS/AuthenticationMethod.cs
@@ -6,6 +6,6 @@
public abstract class AuthenticationMethod
{
public abstract ServiceBusAdministrationClient BuildManagementClient();
- public abstract AzureServiceBusTransport CreateTransportDefinition(ConnectionSettings connectionSettings);
+ public abstract AzureServiceBusTransport CreateTransportDefinition(ConnectionSettings connectionSettings, TopicTopology topology);
}
}
\ No newline at end of file
diff --git a/src/ServiceControl.Transports.ASBS/Helper.cs b/src/ServiceControl.Transports.ASBS/Helper.cs
deleted file mode 100644
index 8d73edc2bf..0000000000
--- a/src/ServiceControl.Transports.ASBS/Helper.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-namespace ServiceControl.Transports.ASBS
-{
- using System;
- using System.Security.Cryptography;
- using System.Text;
- using NServiceBus;
-
- public static class Helper
- {
- public static void ConfigureNameShorteners(this AzureServiceBusTransport transport)
- {
- transport.SubscriptionNamingConvention = n => n.Length > MaxEntityName ? MD5DeterministicNameBuilder.Build(n) : n;
- transport.SubscriptionRuleNamingConvention = n => n.FullName.Length > MaxEntityName ? MD5DeterministicNameBuilder.Build(n.FullName) : n.FullName;
- }
-
- const int MaxEntityName = 50;
-
- static class MD5DeterministicNameBuilder
- {
- public static string Build(string input)
- {
- var inputBytes = Encoding.Default.GetBytes(input);
-
- // use MD5 hash to get a 16-byte hash of the string
- var hashBytes = MD5.HashData(inputBytes);
-
- // generate a guid from the hash:
- return new Guid(hashBytes).ToString();
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ServiceControl.Transports.ASBS/SharedAccessSignatureAuthentication.cs b/src/ServiceControl.Transports.ASBS/SharedAccessSignatureAuthentication.cs
index 4539f883d0..5368353371 100644
--- a/src/ServiceControl.Transports.ASBS/SharedAccessSignatureAuthentication.cs
+++ b/src/ServiceControl.Transports.ASBS/SharedAccessSignatureAuthentication.cs
@@ -12,7 +12,7 @@ public class SharedAccessSignatureAuthentication : AuthenticationMethod
public override ServiceBusAdministrationClient BuildManagementClient()
=> new ServiceBusAdministrationClient(ConnectionString);
- public override AzureServiceBusTransport CreateTransportDefinition(ConnectionSettings connectionSettings)
- => new AzureServiceBusTransport(ConnectionString);
+ public override AzureServiceBusTransport CreateTransportDefinition(ConnectionSettings connectionSettings, TopicTopology topology)
+ => new AzureServiceBusTransport(ConnectionString, topology);
}
}
\ No newline at end of file
diff --git a/src/ServiceControl.Transports.ASBS/TokenCredentialAuthentication.cs b/src/ServiceControl.Transports.ASBS/TokenCredentialAuthentication.cs
index 4bbf898096..a11f74463f 100644
--- a/src/ServiceControl.Transports.ASBS/TokenCredentialAuthentication.cs
+++ b/src/ServiceControl.Transports.ASBS/TokenCredentialAuthentication.cs
@@ -4,7 +4,6 @@
using Azure.Identity;
using Azure.Messaging.ServiceBus.Administration;
using NServiceBus;
- using NServiceBus.Transport;
public class TokenCredentialAuthentication : AuthenticationMethod
{
@@ -30,9 +29,9 @@ public TokenCredentialAuthentication(string fullyQualifiedNamespace, string clie
public override ServiceBusAdministrationClient BuildManagementClient()
=> new ServiceBusAdministrationClient(FullyQualifiedNamespace, Credential);
- public override AzureServiceBusTransport CreateTransportDefinition(ConnectionSettings connectionSettings)
+ public override AzureServiceBusTransport CreateTransportDefinition(ConnectionSettings connectionSettings, TopicTopology topology)
{
- var transport = new AzureServiceBusTransport(FullyQualifiedNamespace, Credential);
+ var transport = new AzureServiceBusTransport(FullyQualifiedNamespace, Credential, topology);
return transport;
}
}
diff --git a/src/ServiceControl.Transports/ServiceControl.Transports.csproj b/src/ServiceControl.Transports/ServiceControl.Transports.csproj
index 9d2526b3e9..6bd8eeea61 100644
--- a/src/ServiceControl.Transports/ServiceControl.Transports.csproj
+++ b/src/ServiceControl.Transports/ServiceControl.Transports.csproj
@@ -4,6 +4,11 @@
net8.0
+
+
+
+
+