Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional samples #30430

Merged
merged 9 commits into from
Aug 10, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{8B8C
samples\Sample10_ClaimCheck.md = samples\Sample10_ClaimCheck.md
samples\Sample11_CloudEvents.md = samples\Sample11_CloudEvents.md
samples\Sample12_ManagingRules.md = samples\Sample12_ManagingRules.md
samples\Sample13_AdvancedConfiguration.md = samples\Sample13_AdvancedConfiguration.md
samples\Sample14_AMQPMessage.md = samples\Sample14_AMQPMessage.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Core.Amqp", "..\..\core\Azure.Core.Amqp\src\Azure.Core.Amqp.csproj", "{2ADA26CA-77E5-4793-927A-A6185FD8AA29}"
Expand Down
18 changes: 0 additions & 18 deletions sdk/servicebus/Azure.Messaging.ServiceBus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ We guarantee that all client instance methods are thread-safe and independent of
* [Dead letter a message](#dead-letter-a-message)
* [Using the processor](#using-the-processor)
* [Authenticating with Azure.Identity](#authenticating-with-azureidentity)
* [Initiating the connection with a custom endpoint](#initiating-the-connection-with-a-custom-endpoint)
* [Working with sessions](#working-with-sessions)
* [More samples](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/servicebus/Azure.Messaging.ServiceBus/samples/README.md)

Expand Down Expand Up @@ -419,23 +418,6 @@ string fullyQualifiedNamespace = "yournamespace.servicebus.windows.net";
ServiceBusClient client = new ServiceBusClient(fullyQualifiedNamespace, new DefaultAzureCredential());
```

### Initiating the connection with a custom endpoint
JoshLove-msft marked this conversation as resolved.
Show resolved Hide resolved

If an alternative host name is needed to establish the connection to the service, a custom endpoint address can be provided through the `ServiceBusClientOptions`. The client will use this endpoint to open the initial connection, and then will use the default endpoint provided by the Service Bus service for all following operations and validation.

```C# Snippet:ServiceBusCustomEndpoint
// Connect to the service using a custom endpoint
string connectionString = "<connection_string>";
string customEndpoint = "<custom_endpoint>";

var options = new ServiceBusClientOptions
{
CustomEndpointAddress = new Uri(customEndpoint)
};

ServiceBusClient client = new ServiceBusClient(connectionString, options);
```

### Working with Sessions

[Sessions](https://docs.microsoft.com/azure/service-bus-messaging/message-sessions) provide a mechanism for grouping related messages. In order to use sessions, you need to be working with a session-enabled entity.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Sending and Receiving Messages

This sample demonstrates how to send and receive messages from a Service Bus queue.
This sample demonstrates how to send and receive messages from a Service Bus queue. Once a message is received, you will typically want to settle it. Message settlement is covered in detail in the [Settling Messages samples](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/servicebus/Azure.Messaging.ServiceBus/samples/Sample02_MessageSettlement.md).

### Send and receive a message using queues

Expand Down Expand Up @@ -140,7 +140,7 @@ foreach (ServiceBusReceivedMessage receivedMessage in receivedMessages)

## Peeking a message

It's also possible to simply peek a message. Peeking a message does not require the message to be locked.
It's also possible to simply peek a message. Peeking a message does not require the message to be locked. Because the message is not locked to a specific receiver, the message will not be able to be settled.
JoshLove-msft marked this conversation as resolved.
Show resolved Hide resolved

```C# Snippet:ServiceBusPeek
ServiceBusReceivedMessage peekedMessage = await receiver.PeekMessageAsync();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Sending and Receiving Session Messages
# Sending and Receiving Session Messages

This sample demonstrates how to send and receive session messages from a session-enabled Service Bus queue.

JoshLove-msft marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Using the Processor
# Using the Processor

This sample demonstrates how to use the processor. The processor offers automatic completion of processed messages, automatic message lock renewal, and concurrent execution of user specified event handlers.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Using the Session Processor
# Using the Session Processor

This sample demonstrates how to use the session processor. The session processor offers automatic completion of processed session messages, automatic session lock renewal, and concurrent execution of user specified event handlers.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Working with transactions
# Working with transactions

This sample demonstrates how to use [transactions](https://docs.microsoft.com/azure/service-bus-messaging/service-bus-transactions) with Service Bus. Transactions allow you to group operations together so that either all of them complete or none of them do. If any part of the transaction fails, the service will rollback the parts that succeeded on your behalf. You also can use familiar .NET semantics to complete or rollback the transaction using [TransactionScope](https://docs.microsoft.com/dotnet/api/system.transactions.transactionscope?view=netcore-3.1).

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## CRUD operations
# CRUD operations

This sample demonstrates how to use the management client to manage entities within a namespace.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Interop with `WindowsAzure.ServiceBus`
# Interop with `WindowsAzure.ServiceBus`

This sample demonstrates how to interoperate with messages that are sent or received using the `WindowsAzure.ServiceBus` library. The `WindowsAzure.ServiceBus` library uses the `DataContractSerializer` to serialize the `BrokeredMessage` body. Because of this, when attempting to interoperate with this library, there a few additional steps that are needed.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Extensibility
# Extensibility

This sample demonstrates how the key Service Bus types can be extended to provide custom functionality. As an example, we will demonstrate how messages can be intercepted and enriched before sending and after receiving. This mimics the functionality enabled by the `RegisterPlugin` method on client types in `Microsoft.Azure.ServiceBus`.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Claim check pattern
# Claim check pattern

This sample demonstrates the use of the [claim check pattern](https://docs.microsoft.com/azure/architecture/patterns/claim-check) which enables you to work with arbitrarily large message bodies. For standard namespaces, a message can be at most 256 KB. For Premium namespaces, the limit is 100 MB. If these limits don't work for your application you can leverage Azure Storage Blobs to implement this pattern.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Integrating with the CloudEvent type
# Integrating with the CloudEvent type

The Azure.Core library contains the [CloudEvent](https://docs.microsoft.com/dotnet/api/azure.messaging.cloudevent) type which conforms to the [CloudEvent JSON spec](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/formats/json-format.md). This type can be used in conjunction with the Service Bus library as shown below:

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Managing Rules
# Managing Rules

As shown in the [CRUD operations sample](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/servicebus/Azure.Messaging.ServiceBus/samples/Sample07_CrudOperations.md), rules can be created, deleted, and retrieved using the `ServiceBusAdministrationClient`. In order to perform these operations, you need to have `Manage` rights to the Service Bus namespace. When using Azure Identity, this translates to requiring the [Service Bus Data Owner role](https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#azure-service-bus-data-owner) be granted to your identity. It is also possible to perform these rule management operations using the `ServiceBusRuleManager` type. The major benefit to using this type is that you only need `Listen` rights for the subscription you wish to manage rules for, which corresponds to the [Service Bus Data Receiver role](https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#azure-service-bus-data-receiver). The following snippet provides an example of how to use this type.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Advanced Configuration
JoshLove-msft marked this conversation as resolved.
Show resolved Hide resolved

This sample demonstrates how to use some of the advanced configuration options available in the Service Bus client library.

## Configuring the transport

By default, the Service Bus client library communicates with the service using the AMQP protocol over TCP. Some application host environments prefer to restrict raw TCP socket use, especially in many enterprise or VPN scenarios. In these environments, or when a proxy is in use, communication with the Event Hubs service can make use of web sockets by configuring the client's connection settings.

In the example shown below, the transport is configured to use web sockets and a proxy is specified. You can also use websockets without specifying a proxy, but the proxy should only be used when using websockets.

```C# Snippet:ServiceBusConfigureTransport
var client = new ServiceBusClient("<connection-string>", new ServiceBusClientOptions
{
TransportType = ServiceBusTransportType.AmqpWebSockets,
WebProxy = new WebProxy("<proxy-address>")
});
```

## Initiating the connection with a custom endpoint

If an alternative host name is needed to establish the connection to the service, a custom endpoint address can be provided through the `ServiceBusClientOptions`. The client will use this endpoint to open the initial connection, and then will use the default endpoint provided by the Service Bus service for all following operations and validation.

```C# Snippet:ServiceBusCustomEndpoint
// Connect to the service using a custom endpoint
string connectionString = "<connection_string>";
string customEndpoint = "<custom_endpoint>";

var options = new ServiceBusClientOptions
{
CustomEndpointAddress = new Uri(customEndpoint)
};

ServiceBusClient client = new ServiceBusClient(connectionString, options);
```

## Customizing the retry options

The retry options are used to configure the retry policy for all operations when communicating with the service. The default values are shown below, but they can be customized to fit your scenario.

```C# Snippet:ServiceBusConfigureRetryOptions
var client = new ServiceBusClient("<connection-string>", new ServiceBusClientOptions
{
RetryOptions = new ServiceBusRetryOptions
{
TryTimeout = TimeSpan.FromSeconds(60),
MaxRetries = 3,
Delay = TimeSpan.FromSeconds(.8)
}
});
```

## Using Prefetch

The [prefetch feature](https://docs.microsoft.com/azure/service-bus-messaging/service-bus-prefetch?tabs=dotnet) allows the receiver and processor to request messages in the background before an actual receive operation is initiated. This can potentially increase the throughput of your application, but it comes with several large drawbacks that are outlined in this [document](https://docs.microsoft.com/azure/service-bus-messaging/service-bus-prefetch?tabs=dotnet#why-is-prefetch-not-the-default-option). If you determine that prefetch makes sense for your application here is how you would enable it:

```C# Snippet:ServiceBusConfigurePrefetchReceiver
var client = new ServiceBusClient("<connection-string>");
ServiceBusReceiver receiver = client.CreateReceiver("<queue-name>", new ServiceBusReceiverOptions
{
PrefetchCount = 10
});
```

And when using the processor:

```C# Snippet:ServiceBusConfigurePrefetchProcessor
var client = new ServiceBusClient("<connection-string>");
ServiceBusProcessor processor = client.CreateProcessor("<queue-name>", new ServiceBusProcessorOptions
{
PrefetchCount = 10
});
```

## Source

To see the full example source, see:

* [Sample13_AdvancedConfiguration.cs](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/servicebus/Azure.Messaging.ServiceBus/tests/Samples/Sample13_AdvancedConfiguration.cs)
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Interact with the AMQP message

This sample demonstrates how to interact with the underlying AMQP message that `ServiceBusMessage` and `ServiceBusReceivedMessage` types are built from.

## Message Body

The most common scenario where you may need to peek into the underlying AMQP message is in interop scenarios where you are receiving a message that has a non-standard body. The [AMQP spec](https://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-messaging-v1.0-os.html#section-message-format) allows three types of message body: a series of data sections, a value section, or a series of sequence sections. When using the `ServiceBusMessage.Body` property, you are implicitly using a single `data` section for the message body. If you are consuming from a queue or subscription in which the producer is either using a different client, or this client but setting the message body as a value or sequence, you would need to do the following:

```C# Snippet:ServiceBusInspectMessageBody
ServiceBusReceiver receiver = client.CreateReceiver(queueName);
JoshLove-msft marked this conversation as resolved.
Show resolved Hide resolved
ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();

AmqpAnnotatedMessage amqpMessage = receivedMessage.GetRawAmqpMessage();
if (amqpMessage.Body.TryGetValue(out object value))
{
// handle the value body
}
else if (amqpMessage.Body.TryGetSequence(out IEnumerable<IList<object>> sequence))
{
// handle the sequence body
}
else if (amqpMessage.Body.TryGetData(out IEnumerable<ReadOnlyMemory<byte>> data))
{
// handle the data body - note that unlike when accessing the Body property of the received message,
// we actually get back a list of byte arrays, not a single byte array. If you were to access the Body property,
// the data would be flattened into a single byte array.
}
```

If you needed to send a value body, you could do the following:

```C# Snippet:ServiceBusSendValueBody
var client = new ServiceBusClient(connectionString);
ServiceBusSender sender = client.CreateSender(queueName);

var message = new ServiceBusMessage();
message.GetRawAmqpMessage().Body = AmqpMessageBody.FromValue(42);
await sender.SendMessageAsync(message);
```

## Setting Miscellaneous Properties
JoshLove-msft marked this conversation as resolved.
Show resolved Hide resolved

You can also set various properties on the AMQP message that are not exposed on the `ServiceBusMessage` type. These values are not granted special meaning by the Service Bus broker and therefore do not impact the Service Bus service behavior. However, since these are standard AMQP properties, they could impact the behavior of other message brokers that may receive these messages.

```C# Snippet:ServiceBusSetMiscellaneousProperties
var client = new ServiceBusClient(connectionString);
ServiceBusSender sender = client.CreateSender(queueName);

var message = new ServiceBusMessage("message with AMQP properties set");
AmqpAnnotatedMessage amqpMessage = message.GetRawAmqpMessage();

// set some properties of the AMQP header
amqpMessage.Header.Durable = true;
amqpMessage.Header.Priority = 1;

// set some custom properties in the footer
amqpMessage.Footer["custom-footer-property"] = "custom-footer-value";

// set some custom properties in the message annotations
amqpMessage.MessageAnnotations["custom-message-annotation"] = "custom-message-annotation-value";

// set some custom properties in the delivery annotations
amqpMessage.DeliveryAnnotations["custom-delivery-annotation"] = "custom-delivery-annotation-value";
await sender.SendMessageAsync(message);
```

You can also retrieve these properties when receiving a message:

```C# Snippet:ServiceBusGetMiscellaneousProperties
ServiceBusReceiver receiver = client.CreateReceiver(queueName);
ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();

AmqpAnnotatedMessage receivedAmqpMessage = receivedMessage.GetRawAmqpMessage();
AmqpMessageHeader header = receivedAmqpMessage.Header;

bool? durable = header.Durable;
byte? priority = header.Priority;
string customFooterValue = (string)receivedAmqpMessage.Footer["custom-footer-property"];
string customMessageAnnotation = (string)receivedAmqpMessage.MessageAnnotations["custom-message-annotation"];
string customDeliveryAnnotation = (string)receivedAmqpMessage.DeliveryAnnotations["custom-delivery-annotation"];
```

## Source

To see the full example source, see:

* [Sample14_AMQPMessage.cs](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/servicebus/Azure.Messaging.ServiceBus/tests/Samples/Sample14_AMQPMessage.cs)
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,19 @@ public static ServiceBusReceivedMessage AmqpMessageToSBMessage(AmqpMessage amqpM

// footer

if ((sections & SectionFlag.Footer) != 0)
JoshLove-msft marked this conversation as resolved.
Show resolved Hide resolved
{
foreach (KeyValuePair<MapKey, object> kvp in amqpMessage.Footer.Map)
{
if (TryGetNetObjectFromAmqpObject(kvp.Value, MappingType.ApplicationProperty, out var netObject))
{
annotatedMessage.Footer[kvp.Key.ToString()] = netObject;
}
}
}

// lock token

if (amqpMessage.DeliveryTag.Count == GuidSizeInBytes)
{
Span<byte> guidBytes = stackalloc byte[GuidSizeInBytes];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,10 @@ await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitionin
// delivery annotations
Assert.AreEqual(received.DeliveryAnnotations["deliveryAnnotationKey1"], "deliveryAnnotationVal1");
Assert.AreEqual(received.DeliveryAnnotations["deliveryAnnotationKey2"], "deliveryAnnotationVal2");

// footer
Assert.AreEqual("footerVal1", received.Footer["footerKey1"]);
Assert.AreEqual("footerVal2", received.Footer["footerKey2"]);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ public void AuthenticateWithAAD()
}

/// <summary>
/// Authenticate with a connection string/>.
/// Authenticate with a connection string.
/// </summary>
public void AuthenticateWithConnectionString()
{
Expand All @@ -307,7 +307,7 @@ public void AuthenticateWithConnectionString()
}

/// <summary>
/// Connect to the service using a custom endpoint address/>.
/// Connect to the service using a custom endpoint address.
/// </summary>
public void ConnectUsingCustomEndpoint()
{
Expand Down