diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/README.md b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/README.md index 630a8b3d4936f..8dedea4a12c60 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/README.md +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/README.md @@ -54,6 +54,8 @@ For the Event Hubs client library to interact with an Event Hub, it will need to For the event processor client to make use of Azure Storage blobs for checkpointing, it will need to understand how to connect to a storage account and authorize with it. The most straightforward method of doing so is to use a connection string, which is generated at the time that the storage account is created. If you aren't familiar with storage account connection string authorization in Azure, you may wish to follow the step-by-step guide to [configure Azure Storage connection strings](https://docs.microsoft.com/azure/storage/common/storage-configure-connection-string). +Once you have the connection strings, see [Creating an Event Processor Client](#creating-an-event-processor-client) for an example of how to use them to create the processor. + ## Key concepts - An **event processor** is a construct intended to manage the responsibilities associated with connecting to a given Event Hub and processing events from each of its partitions, in the context of a specific consumer group. The act of processing events read from the partition and handling any errors that occur is delegated by the event processor to code that you provide, allowing your logic to concentrate on delivering business value while the processor handles the tasks associated with reading events, managing the partitions, and allowing state to be persisted in the form of checkpoints. diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/README.md b/sdk/eventhub/Azure.Messaging.EventHubs/README.md index 6eed5aa7e6f5a..a39deacfd48a0 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs/README.md +++ b/sdk/eventhub/Azure.Messaging.EventHubs/README.md @@ -44,6 +44,24 @@ dotnet add package Azure.Messaging.EventHubs ### Authenticate the client For the Event Hubs client library to interact with an Event Hub, it will need to understand how to connect and authorize with it. The easiest means for doing so is to use a connection string, which is created automatically when creating an Event Hubs namespace. If you aren't familiar with using connection strings with Event Hubs, you may wish to follow the step-by-step guide to [get an Event Hubs connection string](https://docs.microsoft.com/azure/event-hubs/event-hubs-get-connection-string). + +Once you have a connection string, any of the Event Hubs client types can be created with it: + +```C# Snippet:EventHubs_ReadMe_Create_ConnectionString +var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; +var eventHubName = "<< NAME OF THE EVENT HUB >>"; + +// It is recommended that you cache the Event Hubs clients for the lifetime of your +// application, closing or disposing when application ends. This example disposes +// after the immediate scope for simplicity. + +await using var producer = new EventHubProducerClient(connectionString, eventHubName); +``` + +For examples of authenticating the Event Hubs clients with credential types, see [Using an Azure Active Directory (AAD) principal](#using-an-active-directory-principal-with-the-event-hub-clients) or the [Identity and Shared Access Credentials](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/eventhub/Azure.Messaging.EventHubs/samples/Sample06_IdentityAndSharedAccessCredentials.md) sample. + +For examples of authenticating the Event Hubs clients for an ASP.NET Core application, see [Registering with ASP.NET Core dependency injection](#registering-with-aspnet-core-dependency-injection). + ## Key concepts - An **Event Hub client** is the primary interface for developers interacting with the Event Hubs client library. There are several different Event Hub clients, each dedicated to a specific use of Event Hubs, such as publishing or consuming events. @@ -85,6 +103,10 @@ Many Event Hub operations take place within the scope of a specific partition. var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; var eventHubName = "<< NAME OF THE EVENT HUB >>"; +// It is recommended that you cache the Event Hubs clients for the lifetime of your +// application, closing or disposing when application ends. This example disposes +// after the immediate scope for simplicity. + await using (var producer = new EventHubProducerClient(connectionString, eventHubName)) { string[] partitionIds = await producer.GetPartitionIdsAsync(); @@ -99,11 +121,19 @@ In order to publish events, you'll need to create an `EventHubProducerClient`. var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; var eventHubName = "<< NAME OF THE EVENT HUB >>"; +// It is recommended that you cache the Event Hubs clients for the lifetime of your +// application, closing or disposing when application ends. This example disposes +// after the immediate scope for simplicity. + await using (var producer = new EventHubProducerClient(connectionString, eventHubName)) { using EventDataBatch eventBatch = await producer.CreateBatchAsync(); - eventBatch.TryAdd(new EventData(new BinaryData("First"))); - eventBatch.TryAdd(new EventData(new BinaryData("Second"))); + + if ((!eventBatch.TryAdd(new EventData("First"))) || + (!eventBatch.TryAdd(new EventData("Second")))) + { + throw new ApplicationException("Not all events could be added to the batch!"); + } await producer.SendAsync(eventBatch); } @@ -121,6 +151,10 @@ var eventHubName = "<< NAME OF THE EVENT HUB >>"; string consumerGroup = EventHubConsumerClient.DefaultConsumerGroupName; +// It is recommended that you cache the Event Hubs clients for the lifetime of your +// application, closing or disposing when application ends. This example disposes +// after the immediate scope for simplicity. + await using (var consumer = new EventHubConsumerClient(consumerGroup, connectionString, eventHubName)) { using var cancellationSource = new CancellationTokenSource(); @@ -146,6 +180,10 @@ var eventHubName = "<< NAME OF THE EVENT HUB >>"; string consumerGroup = EventHubConsumerClient.DefaultConsumerGroupName; +// It is recommended that you cache the Event Hubs clients for the lifetime of your +// application, closing or disposing when application ends. This example disposes +// after the immediate scope for simplicity. + await using (var consumer = new EventHubConsumerClient(consumerGroup, connectionString, eventHubName)) { EventPosition startingPosition = EventPosition.Earliest; @@ -221,7 +259,7 @@ More details can be found in the Event Processor Client [README](https://github. ### Using an Active Directory principal with the Event Hub clients -The [Azure Identity library](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/README.md) provides Azure Active Directory authentication support which can be used for the Azure client libraries, including Event Hubs. +The [Azure Identity library](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/README.md) provides Azure Active Directory (AAD) authentication support which can be used for the Azure client libraries, including Event Hubs. To make use of an Active Directory principal, one of the available credentials from the `Azure.Identity` library is specified when creating the Event Hubs client. In addition, the fully qualified Event Hubs namespace and the name of desired Event Hub are supplied in lieu of the Event Hubs connection string. For illustration, the `EventHubProducerClient` is demonstrated in these examples, but the concept and form are common across clients. @@ -230,11 +268,19 @@ var fullyQualifiedNamespace = "<< FULLY-QUALIFIED EVENT HUBS NAMESPACE (like som var eventHubName = "<< NAME OF THE EVENT HUB >>"; var credential = new DefaultAzureCredential(); +// It is recommended that you cache the Event Hubs clients for the lifetime of your +// application, closing or disposing when application ends. This example disposes +// after the immediate scope for simplicity. + await using (var producer = new EventHubProducerClient(fullyQualifiedNamespace, eventHubName, credential)) { using EventDataBatch eventBatch = await producer.CreateBatchAsync(); - eventBatch.TryAdd(new EventData(new BinaryData("First"))); - eventBatch.TryAdd(new EventData(new BinaryData("Second"))); + + if ((!eventBatch.TryAdd(new EventData("First"))) || + (!eventBatch.TryAdd(new EventData("Second")))) + { + throw new ApplicationException("Not all events could be added to the batch!"); + } await producer.SendAsync(eventBatch); } @@ -242,6 +288,62 @@ await using (var producer = new EventHubProducerClient(fullyQualifiedNamespace, When using Azure Active Directory, your principal must be assigned a role which allows access to Event Hubs, such as the `Azure Event Hubs Data Owner` role. For more information about using Azure Active Directory authorization with Event Hubs, please refer to [the associated documentation](https://docs.microsoft.com/azure/event-hubs/authorize-access-azure-active-directory). +### Registering with ASP.NET Core dependency injection + +To inject one of the Event Hubs clients as a dependency in an ASP.NET Core application, install the Azure client library integration for ASP.NET Core package. + +```dotnetcli +dotnet add package Microsoft.Extensions.Azure +``` + +After installing, register the desired Event Hubs client types in the `Startup.ConfigureServices` method: + +```csharp +public void ConfigureServices(IServiceCollection services) +{ + services.AddAzureClients(builder => + { + builder.AddEventHubProducerClient(Configuration.GetConnectionString("EventHubs")); + }); + + services.AddControllers(); +} +``` + +To use the preceding code, add this to the configuration for your application: + +```json +{ + "ConnectionStrings": { + "EventHubs": "" + } +} +``` + +For applications that prefer using a shared `Azure.Identity` credential for their clients, registration looks slightly different: + +```csharp +var fullyQualifiedNamespace = "<< FULLY-QUALIFIED EVENT HUBS NAMESPACE (like something.servicebus.windows.net) >>"; + +public void ConfigureServices(IServiceCollection services) +{ + services.AddAzureClients(builder => + { + // This will register the EventHubProducerClient using the default credential. + builder.AddEventHubProducerClientWithNamespace(fullyQualifiedNamespace); + + // By default, DefaultAzureCredential is used, which is likely desired for most + // scenarios. If you need to restrict to a specific credential instance, you could + // register that instance as the default credential instead. + builder.UseCredential(new ManagedIdentityCredential()); + }); + + services.AddControllers(); +} +``` + +For more details, see [Dependency injection with the Azure SDK for .NET](https://docs.microsoft.com/dotnet/azure/sdk/dependency-injection). + ## Troubleshooting For detailed troubleshooting information, please refer to the [Event Hubs Troubleshooting Guide](https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/eventhub/Azure.Messaging.EventHubs/TROUBLESHOOTING.md). diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/ApiCompatBaseline.txt b/sdk/eventhub/Azure.Messaging.EventHubs/src/ApiCompatBaseline.txt deleted file mode 100644 index 49784d2611a57..0000000000000 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/ApiCompatBaseline.txt +++ /dev/null @@ -1,2 +0,0 @@ -# Baselining these until the next GA. This is not a compatibility issue; the impacted member was inappropriately tagged as non-visible and provides value for customers being discoverable. -CannotRemoveAttribute : Attribute 'System.ComponentModel.EditorBrowsableAttribute' exists on 'Azure.Messaging.EventHubs.Consumer.EventPosition.ToString()' in the contract but not the implementation. diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Snippets/ReadMeSnippetsLiveTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Snippets/ReadMeSnippetsLiveTests.cs index 9f5e4e96df07e..14d6f446a2d39 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Snippets/ReadMeSnippetsLiveTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Snippets/ReadMeSnippetsLiveTests.cs @@ -23,6 +23,32 @@ namespace Azure.Messaging.EventHubs.Tests.Snippets [Category(TestCategory.DisallowVisualStudioLiveUnitTesting)] public class ReadMeSnippetsLiveTests { + /// + /// Performs basic smoke test validation of the contained snippet. + /// + /// + [Test] + public async Task CreateWithConnectionString() + { + #region Snippet:EventHubs_ReadMe_Create_ConnectionString + +#if SNIPPET + var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; + var eventHubName = "<< NAME OF THE EVENT HUB >>"; +#else + var connectionString = EventHubsTestEnvironment.Instance.EventHubsConnectionString; + var eventHubName = "fakeHub"; +#endif + + // It is recommended that you cache the Event Hubs clients for the lifetime of your + // application, closing or disposing when application ends. This example disposes + // after the immediate scope for simplicity. + + await using var producer = new EventHubProducerClient(connectionString, eventHubName); + + #endregion + } + /// /// Performs basic smoke test validation of the contained snippet. /// @@ -42,6 +68,10 @@ public async Task Inspect() var eventHubName = scope.EventHubName; #endif + // It is recommended that you cache the Event Hubs clients for the lifetime of your + // application, closing or disposing when application ends. This example disposes + // after the immediate scope for simplicity. + await using (var producer = new EventHubProducerClient(connectionString, eventHubName)) { string[] partitionIds = await producer.GetPartitionIdsAsync(); @@ -69,11 +99,19 @@ public async Task Publish() var eventHubName = scope.EventHubName; #endif + // It is recommended that you cache the Event Hubs clients for the lifetime of your + // application, closing or disposing when application ends. This example disposes + // after the immediate scope for simplicity. + await using (var producer = new EventHubProducerClient(connectionString, eventHubName)) { using EventDataBatch eventBatch = await producer.CreateBatchAsync(); - eventBatch.TryAdd(new EventData(new BinaryData("First"))); - eventBatch.TryAdd(new EventData(new BinaryData("Second"))); + + if ((!eventBatch.TryAdd(new EventData("First"))) || + (!eventBatch.TryAdd(new EventData("Second")))) + { + throw new ApplicationException("Not all events could be added to the batch!"); + } await producer.SendAsync(eventBatch); } @@ -104,6 +142,10 @@ public async Task Read() string consumerGroup = EventHubConsumerClient.DefaultConsumerGroupName; + // It is recommended that you cache the Event Hubs clients for the lifetime of your + // application, closing or disposing when application ends. This example disposes + // after the immediate scope for simplicity. + await using (var consumer = new EventHubConsumerClient(consumerGroup, connectionString, eventHubName)) { using var cancellationSource = new CancellationTokenSource(); @@ -149,6 +191,10 @@ public async Task ReadPartition() string consumerGroup = EventHubConsumerClient.DefaultConsumerGroupName; + // It is recommended that you cache the Event Hubs clients for the lifetime of your + // application, closing or disposing when application ends. This example disposes + // after the immediate scope for simplicity. + await using (var consumer = new EventHubConsumerClient(consumerGroup, connectionString, eventHubName)) { EventPosition startingPosition = EventPosition.Earliest; @@ -195,11 +241,19 @@ public async Task PublishIdentity() var credential = EventHubsTestEnvironment.Instance.Credential; #endif + // It is recommended that you cache the Event Hubs clients for the lifetime of your + // application, closing or disposing when application ends. This example disposes + // after the immediate scope for simplicity. + await using (var producer = new EventHubProducerClient(fullyQualifiedNamespace, eventHubName, credential)) { using EventDataBatch eventBatch = await producer.CreateBatchAsync(); - eventBatch.TryAdd(new EventData(new BinaryData("First"))); - eventBatch.TryAdd(new EventData(new BinaryData("Second"))); + + if ((!eventBatch.TryAdd(new EventData("First"))) || + (!eventBatch.TryAdd(new EventData("Second")))) + { + throw new ApplicationException("Not all events could be added to the batch!"); + } await producer.SendAsync(eventBatch); } diff --git a/sdk/servicebus/Azure.Messaging.ServiceBus/README.md b/sdk/servicebus/Azure.Messaging.ServiceBus/README.md index 557361b2ed968..7c276904e35c8 100755 --- a/sdk/servicebus/Azure.Messaging.ServiceBus/README.md +++ b/sdk/servicebus/Azure.Messaging.ServiceBus/README.md @@ -56,41 +56,9 @@ await using var client = new ServiceBusClient(connectionString); To see how to authenticate using Azure.Identity, view this [example](#authenticating-with-azureidentity). -To see how to initiate the connection with a custom endpoint, view this [sample](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/servicebus/Azure.Messaging.ServiceBus/samples/Sample13_AdvancedConfiguration.md#initiating-the-connection-with-a-custom-endpoint). - -### ASP.NET Core - -To inject `ServiceBusClient` as a dependency in an ASP.NET Core app, install the Azure client library integration for ASP.NET Core package. - -```dotnetcli -dotnet add package Microsoft.Extensions.Azure -``` - -Then register the client in the `Startup.ConfigureServices` method: - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddAzureClients(builder => - { - builder.AddServiceBusClient(Configuration.GetConnectionString("ServiceBus")); - }); - - services.AddControllers(); -} -``` - -To use the preceding code, add this to your configuration: - -```json -{ - "ConnectionStrings": { - "ServiceBus": "" - } -} -``` +For examples of how to authenticate for an ASP.NET Core application, view this [example](#registering-with-aspnet-core-dependency-injection). -For more details, see [Dependency injection with the Azure SDK for .NET](https://docs.microsoft.com/dotnet/azure/sdk/dependency-injection). +To see how to initiate the connection with a custom endpoint, view this [sample](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/servicebus/Azure.Messaging.ServiceBus/samples/Sample13_AdvancedConfiguration.md#initiating-the-connection-with-a-custom-endpoint). ## Key concepts @@ -420,6 +388,62 @@ string fullyQualifiedNamespace = "yournamespace.servicebus.windows.net"; await using var client = new ServiceBusClient(fullyQualifiedNamespace, new DefaultAzureCredential()); ``` +### Registering with ASP.NET Core dependency injection + +To inject `ServiceBusClient` as a dependency in an ASP.NET Core app, install the Azure client library integration for ASP.NET Core package. + +```dotnetcli +dotnet add package Microsoft.Extensions.Azure +``` + +Then register the client in the `Startup.ConfigureServices` method: + +```csharp +public void ConfigureServices(IServiceCollection services) +{ + services.AddAzureClients(builder => + { + builder.AddServiceBusClient(Configuration.GetConnectionString("ServiceBus")); + }); + + services.AddControllers(); +} +``` + +To use the preceding code, add this to the configuration for your application: + +```json +{ + "ConnectionStrings": { + "ServiceBus": "" + } +} +``` + +For applications that prefer using a shared `Azure.Identity` credential for their clients, registration looks slightly different: + +```csharp +var fullyQualifiedNamespace = "yournamespace.servicebus.windows.net"; + +public void ConfigureServices(IServiceCollection services) +{ + services.AddAzureClients(builder => + { + // This will register the ServiceBusClient using the default credential. + builder.AddServiceBusClientWithNamespace(fullyQualifiedNamespace); + + // By default, DefaultAzureCredential is used, which is likely desired for most + // scenarios. If you need to restrict to a specific credential instance, you could + // register that instance as the default credential instead. + builder.UseCredential(new ManagedIdentityCredential()); + }); + + services.AddControllers(); +} +``` + +For more details, see [Dependency injection with the Azure SDK for .NET](https://docs.microsoft.com/dotnet/azure/sdk/dependency-injection). + ### 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.