Skip to content

Commit e4f7120

Browse files
abparticulartmasternak
andauthoredSep 15, 2024··
Document v4 of Messaging Bridge (#6831)
* Document DoNotTranslateReplyToAddressForFailedMessages method for v4 of Messaging Bridge * Initial attempt at upgrade guide for Messaging Bridge from v3 to v4 * Apply suggestions from code review Co-authored-by: Tomasz Masternak <tomasz.masternak@particular.net> * Added new Messaging Bridge upgrade guide to the menu --------- Co-authored-by: Tomasz Masternak <tomasz.masternak@particular.net>
1 parent 3bc9bdb commit e4f7120

10 files changed

+370
-3
lines changed
 

‎Snippets/Bridge/Bridge.sln

+6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bridge_2.3", "Bridge_2.3\Br
1313
EndProject
1414
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bridge_3.1", "Bridge_3.1\Bridge_3.1.csproj", "{3E841EA4-DF6D-4DA4-9704-00EBBA86D335}"
1515
EndProject
16+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bridge_4", "Bridge_4\Bridge_4.csproj", "{E61A61FA-2554-4B7E-826D-180273707999}"
17+
EndProject
1618
Global
1719
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1820
Debug|Any CPU = Debug|Any CPU
@@ -39,6 +41,10 @@ Global
3941
{3E841EA4-DF6D-4DA4-9704-00EBBA86D335}.Debug|Any CPU.Build.0 = Debug|Any CPU
4042
{3E841EA4-DF6D-4DA4-9704-00EBBA86D335}.Release|Any CPU.ActiveCfg = Release|Any CPU
4143
{3E841EA4-DF6D-4DA4-9704-00EBBA86D335}.Release|Any CPU.Build.0 = Release|Any CPU
44+
{E61A61FA-2554-4B7E-826D-180273707999}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45+
{E61A61FA-2554-4B7E-826D-180273707999}.Debug|Any CPU.Build.0 = Debug|Any CPU
46+
{E61A61FA-2554-4B7E-826D-180273707999}.Release|Any CPU.ActiveCfg = Release|Any CPU
47+
{E61A61FA-2554-4B7E-826D-180273707999}.Release|Any CPU.Build.0 = Release|Any CPU
4248
EndGlobalSection
4349
GlobalSection(SolutionProperties) = preSolution
4450
HideSolutionNode = FALSE

‎Snippets/Bridge/Bridge_4/API.cs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using NServiceBus;
2+
3+
public class API
4+
{
5+
public void Configuration()
6+
{
7+
var connectionString = string.Empty;
8+
var bridgeConfiguration = new BridgeConfiguration();
9+
10+
#region bridgeconfiguration
11+
12+
var msmq = new BridgeTransport(new MsmqTransport());
13+
var asb = new BridgeTransport(new AzureServiceBusTransport(connectionString));
14+
15+
msmq.HasEndpoint("Sales");
16+
asb.HasEndpoint("Billing");
17+
18+
bridgeConfiguration.AddTransport(msmq);
19+
bridgeConfiguration.AddTransport(asb);
20+
21+
#endregion
22+
}
23+
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFramework>net8.0-windows</TargetFramework>
4+
</PropertyGroup>
5+
<ItemGroup>
6+
<PackageReference Include="NServiceBus.MessagingBridge" Version="4.*" />
7+
<PackageReference Include="NServiceBus.MessagingBridge.Msmq" Version="3.*" />
8+
<PackageReference Include="NServiceBus.Transport.AzureServiceBus" Version="4.*" />
9+
</ItemGroup>
10+
</Project>
+259
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
using Messages;
2+
using Microsoft.Extensions.Configuration;
3+
using Microsoft.Extensions.Hosting;
4+
using NServiceBus;
5+
using System;
6+
using System.Threading.Tasks;
7+
8+
public class Configuration
9+
{
10+
public async Task GenericHost()
11+
{
12+
#region generic-host
13+
14+
await Host.CreateDefaultBuilder()
15+
.UseNServiceBusBridge(bridgeConfiguration =>
16+
{
17+
// Configure the bridge
18+
})
19+
.Build()
20+
.RunAsync();
21+
22+
#endregion
23+
}
24+
25+
public async Task GenericHostBuilderContext()
26+
{
27+
#region generic-host-builder-context
28+
29+
await Host.CreateDefaultBuilder()
30+
.UseNServiceBusBridge((hostBuilderContext, bridgeConfiguration) =>
31+
{
32+
var connectionString = hostBuilderContext.Configuration.GetValue<string>("MyBridge:AzureServiceBusConnectionString");
33+
var concurrency = hostBuilderContext.Configuration.GetValue<int>("MyBridge:Concurrency");
34+
35+
var transport = new BridgeTransport(new AzureServiceBusTransport(connectionString))
36+
{
37+
Concurrency = concurrency
38+
};
39+
40+
bridgeConfiguration.AddTransport(transport);
41+
42+
// more configuration...
43+
})
44+
.Build()
45+
.RunAsync();
46+
47+
#endregion
48+
}
49+
50+
public async Task EndpointRegistration()
51+
{
52+
#region endpoint-registration
53+
54+
await Host.CreateDefaultBuilder()
55+
.UseNServiceBusBridge((ctx, bridgeConfiguration) =>
56+
{
57+
var msmq = new BridgeTransport(new MsmqTransport());
58+
msmq.HasEndpoint("Sales");
59+
msmq.HasEndpoint("Shipping");
60+
61+
var asb = new BridgeTransport(new AzureServiceBusTransport(connectionString));
62+
asb.HasEndpoint("Finance.Invoicing");
63+
asb.HasEndpoint("Finance.Billing");
64+
65+
bridgeConfiguration.AddTransport(msmq);
66+
bridgeConfiguration.AddTransport(asb);
67+
})
68+
.Build()
69+
.RunAsync();
70+
71+
#endregion
72+
}
73+
74+
public void RegisterPublishers()
75+
{
76+
#region register-publisher
77+
78+
var msmq = new BridgeTransport(new MsmqTransport());
79+
msmq.HasEndpoint("Sales");
80+
msmq.HasEndpoint("Finance.Billing");
81+
82+
var asb = new BridgeTransport(new AzureServiceBusTransport(connectionString));
83+
asb.HasEndpoint("Shipping");
84+
85+
var invoicing = new BridgeEndpoint("Finance.Invoicing");
86+
invoicing.RegisterPublisher(typeof(OrderBilled), "Finance.Billing");
87+
invoicing.RegisterPublisher<OrderShipped>("Shipping");
88+
invoicing.RegisterPublisher("Messages.OrderPlaced", "Sales");
89+
90+
asb.HasEndpoint(invoicing);
91+
92+
#endregion
93+
94+
#region register-publisher-legacy
95+
96+
// Type.AssemblyQualifiedName Property value
97+
invoicing.RegisterPublisher("CreditApproved, CreditScoring.Messages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "Sales");
98+
// Type.AssemblyQualifiedName Property but trimmed without Culture and PublicKeyToken as these are ignored by the message driven pub/sub feature
99+
invoicing.RegisterPublisher("CreditApproved, CreditScoring.Messages, Version=1.0.0.0", "Sales");
100+
101+
102+
#endregion
103+
}
104+
105+
public void AutoCreateQueues()
106+
{
107+
#region auto-create-queues
108+
109+
var msmq = new BridgeTransport(new MsmqTransport())
110+
{
111+
AutoCreateQueues = true
112+
};
113+
114+
var azureServiceBus = new BridgeTransport(new AzureServiceBusTransport(connectionString))
115+
{
116+
AutoCreateQueues = true
117+
};
118+
119+
#endregion
120+
121+
#region auto-create-queues-proxies
122+
123+
msmq.HasEndpoint("Sales");
124+
azureServiceBus.HasEndpoint("Billing");
125+
126+
#endregion
127+
}
128+
129+
public void CustomConcurrency()
130+
{
131+
#region custom-concurrency
132+
133+
var msmq = new BridgeTransport(new MsmqTransport())
134+
{
135+
Concurrency = 10
136+
};
137+
138+
var azureServiceBus = new BridgeTransport(new AzureServiceBusTransport(connectionString))
139+
{
140+
Concurrency = 5
141+
};
142+
143+
#endregion
144+
}
145+
146+
public void CustomErrorQueue()
147+
{
148+
#region custom-error-queue
149+
150+
var msmq = new BridgeTransport(new MsmqTransport())
151+
{
152+
ErrorQueue = "my-msmq-bridge-error-queue"
153+
};
154+
155+
var azureServiceBus = new BridgeTransport(new AzureServiceBusTransport(connectionString))
156+
{
157+
ErrorQueue = "my-asb-bridge-error-queue"
158+
};
159+
160+
#endregion
161+
}
162+
163+
public void CustomTransportName()
164+
{
165+
#region custom-transport-name
166+
167+
var azureServiceBus1 = new BridgeTransport(new AzureServiceBusTransport(connectionStringNamepace1))
168+
{
169+
Name = "asb-namespace-1"
170+
};
171+
172+
var azureServiceBus2 = new BridgeTransport(new AzureServiceBusTransport(connectionStringNamepace2))
173+
{
174+
Name = "asb-namespace-2"
175+
};
176+
177+
#endregion
178+
}
179+
180+
public void PlatformBridging()
181+
{
182+
#region platform-bridging
183+
184+
var transportWhereServiceControlIsInstalled = new BridgeTransport(new MsmqTransport());
185+
186+
transportWhereServiceControlIsInstalled.HasEndpoint("Particular.ServiceControl");
187+
transportWhereServiceControlIsInstalled.HasEndpoint("Particular.Monitoring");
188+
transportWhereServiceControlIsInstalled.HasEndpoint("error");
189+
transportWhereServiceControlIsInstalled.HasEndpoint("audit");
190+
191+
#endregion
192+
}
193+
194+
public void QueueName()
195+
{
196+
#region custom-address
197+
198+
var transport = new BridgeTransport(new MsmqTransport());
199+
transport.HasEndpoint("Finance", "finance@machinename");
200+
201+
var endpoint = new BridgeEndpoint("Sales", "sales@another-machine");
202+
transport.HasEndpoint(endpoint);
203+
204+
#endregion
205+
}
206+
207+
public void DoNotEnforceBestPractices()
208+
{
209+
var bridgeConfiguration = new BridgeConfiguration();
210+
211+
#region do-not-enforce-best-practices
212+
213+
bridgeConfiguration.DoNotEnforceBestPractices();
214+
215+
#endregion
216+
}
217+
218+
public void ConfigureHeartbeats()
219+
{
220+
var bridgeTransport = new BridgeTransport(new AzureServiceBusTransport(connectionString));
221+
222+
#region configure-heartbeats
223+
224+
bridgeTransport.SendHeartbeatTo(
225+
serviceControlQueue: "ServiceControl_Queue",
226+
frequency: TimeSpan.FromSeconds(15),
227+
timeToLive: TimeSpan.FromSeconds(30));
228+
229+
#endregion
230+
}
231+
232+
public void ConfigureCustomChecks()
233+
{
234+
var bridgeTransport = new BridgeTransport(new AzureServiceBusTransport(connectionString));
235+
236+
#region configure-custom-checks
237+
238+
bridgeTransport.ReportCustomChecksTo(
239+
serviceControlQueue: "ServiceControl_Queue",
240+
timeToLive: TimeSpan.FromSeconds(30));
241+
242+
#endregion
243+
}
244+
245+
public void DoNotTranslateReplyToAddressForFailedMessages()
246+
{
247+
var bridgeConfiguration = new BridgeConfiguration();
248+
249+
#region do-not-translate-reply-to-address-for-failed-messages
250+
251+
bridgeConfiguration.DoNotTranslateReplyToAddressForFailedMessages();
252+
253+
#endregion
254+
}
255+
256+
string connectionString = string.Empty;
257+
string connectionStringNamepace1 = string.Empty;
258+
string connectionStringNamepace2 = string.Empty;
259+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using NServiceBus;
2+
3+
class ConfigureTransactionMode
4+
{
5+
void SetExplicitReceiveOnly()
6+
{
7+
#region bridge-configuration-explicit-receive-only-mode
8+
9+
var bridgeConfiguration = new BridgeConfiguration();
10+
11+
bridgeConfiguration.RunInReceiveOnlyTransactionMode();
12+
13+
#endregion
14+
}
15+
}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace Messages
2+
{
3+
public class OrderPlaced
4+
{
5+
}
6+
7+
public class OrderBilled
8+
{
9+
}
10+
11+
public class OrderShipped
12+
{
13+
}
14+
}

‎menu/menu.yaml

+6-2
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,6 @@
191191
Title: Callbacks 1 to 2
192192
- Url: nservicebus/upgrades/sqs-lambda-1to2
193193
Title: AwsLambda SQS 1 to 2
194-
- Url: nservicebus/upgrades/bridge-2to3
195-
Title: Messaging Bridge 2 to 3
196194
- Url: nservicebus/upgrades/9to9.1
197195
Title: NServiceBus 9 to 9.1
198196
- Url: nservicebus/upgrades/9.1to9.2
@@ -322,6 +320,12 @@
322320
Title: Version 2 to 3
323321
- Url: nservicebus/upgrades/gateway-3to4
324322
Title: Version 3 to 4
323+
- Title: Messaging Bridge
324+
Articles:
325+
- Url: nservicebus/upgrades/bridge-2to3
326+
Title: Messaging Bridge 2 to 3
327+
- Url: nservicebus/upgrades/bridge-3to4
328+
Title: Messaging Bridge 3 to 4
325329
- Title: System.Text.Json Serializer
326330
Articles:
327331
- Url: nservicebus/upgrades/community-system-json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
### Error queue
2+
3+
By default, when the bridge transfers a message to the ServiceControl error queue it will attempt to translate the [`NServiceBus.ReplyToAddress`](/nservicebus/messaging/headers.md#messaging-interaction-headers-nservicebus-replytoaddress) message header.
4+
It can only do this successfully if the address in the `ReplyToAddress` header maps to some endpoint registered with the bridge. Therefore all endpoints in the system need to be registered with the bridge. Otherwise, the translation of the `ReplyToAddress` header might fail for some messages, which in turn will be moved to [the bridge error queue](/nservicebus/bridge/configuration.md#recoverability-error-queue).
5+
6+
7+
The translation of the `ReplyToAddress` header value for failed messages can be disabled via a dedicated API setting.
8+
9+
snippet: do-not-translate-reply-to-address-for-failed-messages

‎nservicebus/upgrades/bridge-2to3.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Messaging Bridge Upgrade Version 2 to 3
3-
reviewed: 2023-10-23
3+
reviewed: 2024-09-12
44
component: Bridge
55
isUpgradeGuide: true
66
upgradeGuideCoreVersions:

‎nservicebus/upgrades/bridge-3to4.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
title: Messaging Bridge Upgrade Version 3 to 4
3+
component: Bridge
4+
reviewed: 2024-09-12
5+
isUpgradeGuide: true
6+
---
7+
8+
## All endpoints must be registered with the bridge
9+
10+
Version 4 of the Messaging Bridge will default to translating the `NServiceBus.ReplyToAddress` message header for all messages.
11+
This is a change from previous bridge versions, in which the translation of the header had to be explicitly enabled for failed messages.
12+
13+
This behaviour ensures successful delivery of in-flight messages between endpoints that have changed transports during the lifetime of the message.
14+
15+
> [!NOTE]
16+
> The `TranslateReplyToAddressForFailedMessages()` method is now obsolete and will be removed in the next major version of the bridge. It is necessary to remove invocations of the method after upgrading to version 4.
17+
18+
Since the header may contain a physical address of any endpoint in the system, the change in the behavior requires all endpoints in the system to be registered with the bridge. This ensures that the information necessary for the `NServiceBus.ReplyToAddress` header translation is available when messages are transferred by the bridge.
19+
20+
> [!WARNING]
21+
> If the `NServiceBus.ReplyToAddress` header cannot be translated by the bridge (because the endpoint it refers to is not registered), then the message
22+
will be moved to [the bridge error queue](/nservicebus/bridge/configuration.md#recoverability-error-queue). To prevent the need for retrying messages from the bridge error queue (which requires a custom, transport-specific solution) it is strongly recommended to register all endpoints in the system **before** upgrading to version 4.
23+
24+
Users who still want to prevent the need to register all endpoints with the bridge can use a dedicated API option:
25+
26+
snippet: do-not-translate-reply-to-address-for-failed-messages
27+

0 commit comments

Comments
 (0)
Please sign in to comment.