Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ Now in `Azure.Messaging.ServiceBus`, there is an `EnableCrossEntityTransactions`

The below code snippet shows you how to perform cross-entity transactions.

```C# Snippet:ServiceBusTransactionGroup
```C# Snippet:ServiceBusCrossEntityTransaction
var options = new ServiceBusClientOptions { EnableCrossEntityTransactions = true };
await using var client = new ServiceBusClient(connectionString, options);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))

### Transactions across entities (Unreleased)

When creating senders and receivers that should be part of a cross-entity transaction, you can specify the same `TransactionGroup` string in the options as shown below. When using transaction groups, the first entity that an operation occurs on becomes the entity through which all subsequent sends will be routed through. This enables the service to perform a transaction that is meant to span multiple entities. This means that subsequent entities that perform their first operation need to either be senders, or if they are receivers they need to be on the same entity as the initial entity through which all sends are routed through (otherwise the service would not be able to ensure that the transaction is committed because it cannot route a receive operation through a different entity). For instance, if you have SenderA and ReceiverB that are part of the same transaction group, you would need to receive first with ReceiverB to allow this to work. If you first used SenderA to send to QueueA, and then attempted to receive from QueueB, an `InvalidOperationException` would be thrown. You could still add a ReceiverA to the same transaction group after initially sending to SenderA, since they are both using the same queue. This would be useful if you also had a SenderB that you want to include as part of the transaction group (otherwise there would be no need to use transaction groups as you would be dealing with only one entity).
When creating senders and receivers that should be part of a cross-entity transaction, you can set the `EnableCrossEntityTransaction` property of the `ServiceBusClientOptions` as shown below. When using cross-entity transactions, the first entity that an operation occurs on becomes the entity through which all subsequent sends will be routed through. This enables the service to perform a transaction that is meant to span multiple entities. This means that subsequent entities that perform their first operation need to either be senders, or if they are receivers they need to be on the same entity as the initial entity through which all sends are routed through (otherwise the service would not be able to ensure that the transaction is committed because it cannot route a receive operation through a different entity). For instance, if you have SenderA and ReceiverB that are created from a client with cross-entity transactions enabled, you would need to receive first with ReceiverB to allow this to work. If you first used SenderA to send to QueueA, and then attempted to receive from QueueB, an `InvalidOperationException` would be thrown. You could still receive from a ReceiverA after initially sending to SenderA, since they are both using the same queue. This would be useful if you also had a SenderB that you want to include as part of the transaction (otherwise there would be no need to use cross-entity transactions as you would be dealing with only one entity).

```C# Snippet:ServiceBusTransactionGroup
```C# Snippet:ServiceBusCrossEntityTransaction
var options = new ServiceBusClientOptions { EnableCrossEntityTransactions = true };
await using var client = new ServiceBusClient(connectionString, options);

Expand All @@ -68,15 +68,16 @@ using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
```
In the following snippet, we will look at an incorrect ordering that would cause an `InvalidOperationException` to be thrown.
Bad:
```C# Snippet:ServiceBusTransactionGroupWrongOrder
```C# Snippet:ServiceBusCrossEntityTransactionWrongOrder
var options = new ServiceBusClientOptions { EnableCrossEntityTransactions = true };
await using var client = new ServiceBusClient(connectionString, options);

ServiceBusReceiver receiverA = client.CreateReceiver("queueA");
ServiceBusSender senderB = client.CreateSender("queueB");
ServiceBusSender senderC = client.CreateSender("topicC");

// SenderB becomes the entity through which subsequent "sends" are routed through.
// SenderB becomes the entity through which subsequent "sends" are routed through, since it is the first
// entity on which an operation is performed with the cross-entity transaction client.
await senderB.SendMessageAsync(new ServiceBusMessage());

ServiceBusReceivedMessage receivedMessage = await receiverA.ReceiveMessageAsync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ internal ServiceBusReceivedMessage(): this(body: default)
/// Gets the application properties bag, which can be used for custom message metadata.
/// </summary>
/// <remarks>
/// Only following value types are supported:
/// Only the following value types are supported:
/// byte, sbyte, char, short, ushort, int, uint, long, ulong, float, double, decimal,
/// bool, Guid, string, Uri, DateTime, DateTimeOffset, TimeSpan
/// </remarks>
Expand Down Expand Up @@ -304,7 +304,7 @@ internal set

internal short PartitionId { get; set; }

/// <summary>Gets or sets the original sequence number of the message.</summary>
/// <summary>Gets the original sequence number of the message.</summary>
/// <value>The enqueued sequence number of the message.</value>
/// <remarks>
/// For messages that have been auto-forwarded, this property reflects the sequence number
Expand All @@ -328,7 +328,7 @@ internal set
}
}

/// <summary>Gets or sets the date and time of the sent time in UTC.</summary>
/// <summary>Gets the date and time of the sent time in UTC.</summary>
/// <value>The enqueue time in UTC. </value>
/// <remarks>
/// The UTC instant at which the message has been accepted and stored in the entity.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ public async Task SendAndReceiveMessage()
{
await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: false))
{
string connectionString = TestEnvironment.ServiceBusConnectionString;
string queueName = scope.QueueName;
#region Snippet:ServiceBusSendAndReceive
#region Snippet:ServiceBusSendSingleMessage
//@@ string connectionString = "<connection_string>";
//@@ string queueName = "<queue_name>";
#if SNIPPET
string connectionString = "<connection_string>";
string queueName = "<queue_name>";
#else
string connectionString = TestEnvironment.ServiceBusConnectionString;
string queueName = scope.QueueName;
#endif
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);

Expand Down Expand Up @@ -87,12 +90,14 @@ public async Task SendAndReceiveMessageBatch()
{
await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: false))
{
#region Snippet:ServiceBusInitializeSend
#if SNIPPET
string connectionString = "<connection_string>";
string queueName = "<queue_name>";
#else
string connectionString = TestEnvironment.ServiceBusConnectionString;
string queueName = scope.QueueName;

#region Snippet:ServiceBusInitializeSend
//@@ string connectionString = "<connection_string>";
//@@ string queueName = "<queue_name>";
#endif
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);

Expand Down Expand Up @@ -135,11 +140,13 @@ public async Task SendAndReceiveMessageSafeBatch()
{
await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: false))
{
#if SNIPPET
string connectionString = "<connection_string>";
string queueName = "<queue_name>";
#else
string connectionString = TestEnvironment.ServiceBusConnectionString;
string queueName = scope.QueueName;

//@@ string connectionString = "<connection_string>";
//@@ string queueName = "<queue_name>";
#endif
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ public async Task CompleteMessage()
{
await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: false))
{
#region Snippet:ServiceBusCompleteMessage
#if SNIPPET
string connectionString = "<connection_string>";
string queueName = "<queue_name>";
#else
string connectionString = TestEnvironment.ServiceBusConnectionString;
string queueName = scope.QueueName;
#region Snippet:ServiceBusCompleteMessage
//@@ string connectionString = "<connection_string>";
//@@ string queueName = "<queue_name>";
#endif
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ public async Task SendAndReceiveSessionMessage()
{
await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: true))
{
#region Snippet:ServiceBusSendAndReceiveSessionMessage
#if SNIPPET
string connectionString = "<connection_string>";
string queueName = "<queue_name>";
#else
string connectionString = TestEnvironment.ServiceBusConnectionString;
string queueName = scope.QueueName;
#region Snippet:ServiceBusSendAndReceiveSessionMessage
//@@ string connectionString = "<connection_string>";
//@@ string queueName = "<queue_name>";
#endif
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@ public async Task ProcessMessages()
{
await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: false))
{
#region Snippet:ServiceBusProcessMessages
#if SNIPPET
string connectionString = "<connection_string>";
string queueName = "<queue_name>";
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);
#else
string connectionString = TestEnvironment.ServiceBusConnectionString;
string queueName = scope.QueueName;
await using var client = CreateClient();

#region Snippet:ServiceBusProcessMessages
//@@ string connectionString = "<connection_string>";
//@@ string queueName = "<queue_name>";
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
//@@ await using var client = new ServiceBusClient(connectionString);
#endif

// create the sender
ServiceBusSender sender = client.CreateSender(queueName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@ public async Task ProcessSessionMessages()
{
await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: true))
{
#region Snippet:ServiceBusProcessSessionMessages
#if SNIPPET
string connectionString = "<connection_string>";
string queueName = "<queue_name>";
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);
#else
string connectionString = TestEnvironment.ServiceBusConnectionString;
string queueName = scope.QueueName;
await using var client = CreateClient();

#region Snippet:ServiceBusProcessSessionMessages
//@@ string connectionString = "<connection_string>";
//@@ string queueName = "<queue_name>";
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
//@@ await using var client = new ServiceBusClient(connectionString);
#endif

// create the sender
ServiceBusSender sender = client.CreateSender(queueName);
Expand Down
Loading