This library contains some extensions to Microsoft.ServiceBus.dll library
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
.nuget
ServiceBusExtensions
TestClient
.gitattributes
.gitignore
README.md
ServiceBusExtensions.sln

README.md

Introduction

When a developer tries to use the SendBatch or SendBatchAsync methods exposed by the MessageSender, QueueClient, TopicClient, and EventHubClient classes contained in the Microsoft.ServiceBus.dll, and the batch size is greater than the maximum allowed size for a BrokeredMessage or an EventHub object (at the time of writing, the limit is 256 KB), the method call throws a MessageSizeExceededException. This library contains synchronous and asynchronous extension methods for the MessageSender, QueueClient,TopicClient, and EventHubClient classes that allow to send a batch which size is greater than the maximum allowed size for a batch. In particular, the implementation partitions the batch into one or multiple batches, each smaller than the maximum size allowed, and sends them in a loop, to respect the chronological order of the messages contained in the original batch. The code can be found here.

Solution

The ServiceBusExtensions library contains 4 classes:

  • MessageSenderExtensions: this class exposes the SendPartitionedBatch and SendPartitionedBatchAsync extension methods for the MessageSender class.
  • QueueClientExtensions: this class exposes the SendPartitionedBatch andSendPartitionedBatchAsync extension methods for the QueueClient class.
  • TopicClientExtensions: this class exposes the SendPartitionedBatch andSendPartitionedBatchAsync extension methods for the TopicClient class.
  • EventHubClientExtensions: this class exposes the SendPartitionedBatch andSendPartitionedBatchAsync extension methods for the EventHubClient class.

The TesterClient project contains a Console Application that can be used to test the library

ServiceBusExtensions Library

The following table contains the code of the QueueClientExtensions class. The code for the MessageSenderExtensions and TopicClientExtensions classes is very similar, so I will omit it for simplicity.

#region Using Directives
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.ServiceBus.Messaging;
using System.Threading.Tasks;
#endregion

namespace Microsoft.AzureCat.ServiceBusExtensions { /// <summary> /// This class contains extensions methods for the QueueClient class /// </summary> public static class QueueClientClientExtensions { #region Private Constants //******************************* // Formats //******************************* private const string BrokeredMessageListCannotBeNullOrEmpty = "The brokeredMessageEnumerable parameter cannot be null or empty."; private const string SendPartitionedBatchFormat = "[QueueClient.SendPartitionedBatch] Batch Sent: BatchSizeInBytes=[{0}] MessageCount=[{1}]"; private const string SendPartitionedBatchAsyncFormat = "[QueueClient.SendPartitionedBatchAsync] Batch Sent: BatchSizeInBytes=[{0}] MessageCount=[{1}]"; #endregion

</span><span style="color: #0000FF;">#region</span><span style="color: #000000;"> Public Methods</span><span style="color: #000000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;summary&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> Sends a set of brokered messages (for batch processing). 
</span><span style="color: #808080;">///</span><span style="color: #008000;"> If the batch size is greater than the maximum batch size, 
</span><span style="color: #808080;">///</span><span style="color: #008000;"> the method partitions the original batch into multiple batches, 
</span><span style="color: #808080;">///</span><span style="color: #008000;"> each smaller in size than the maximum batch size.
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;/summary&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="queueClient"&gt;</span><span style="color: #008000;">The current QueueClient object.</span><span style="color: #808080;">&lt;/param&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="brokeredMessageEnumerable"&gt;</span><span style="color: #008000;">The collection of brokered messages to send.</span><span style="color: #808080;">&lt;/param&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="trace"&gt;</span><span style="color: #008000;">true to cause a message to be written; otherwise, false.</span><span style="color: #808080;">&lt;/param&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;returns&gt;</span><span style="color: #008000;">The asynchronous operation.</span><span style="color: #808080;">&lt;/returns&gt;</span><span style="color: #808080;">

public async static Task SendPartitionedBatchAsync(this QueueClient queueClient, IEnumerable<BrokeredMessage> brokeredMessageEnumerable, bool trace = false) { var brokeredMessageList = brokeredMessageEnumerable as IList<BrokeredMessage> ?? brokeredMessageEnumerable.ToList(); if (brokeredMessageEnumerable == null || !brokeredMessageList.Any()) { throw new ArgumentNullException(BrokeredMessageListCannotBeNullOrEmpty); }

  var batchList </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> List</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">BrokeredMessage</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">();
  </span><span style="color: #0000FF;">long</span><span style="color: #000000;"> batchSize </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">;

  </span><span style="color: #0000FF;">foreach</span><span style="color: #000000;"> (var brokeredMessage </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> brokeredMessageList)
  {
    </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> ((batchSize </span><span style="color: #000000;">+</span><span style="color: #000000;"> brokeredMessage.Size) </span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> Constants.MaxBathSizeInBytes)
    {
      </span><span style="color: #008000;">//</span><span style="color: #008000;"> Send current batch</span><span style="color: #008000;">

await queueClient.SendBatchAsync(batchList); Trace.WriteLineIf(trace, string.Format(SendPartitionedBatchAsyncFormat, batchSize, batchList.Count));

      </span><span style="color: #008000;">//</span><span style="color: #008000;"> Initialize a new batch</span><span style="color: #008000;">

batchList = new List<BrokeredMessage> { brokeredMessage }; batchSize = brokeredMessage.Size; } else { // Add the BrokeredMessage to the current batch batchList.Add(brokeredMessage); batchSize += brokeredMessage.Size; } } // The final batch is sent outside of the loop await queueClient.SendBatchAsync(batchList); Trace.WriteLineIf(trace, string.Format(SendPartitionedBatchAsyncFormat, batchSize, batchList.Count)); }

</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;summary&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> Sends a set of brokered messages (for batch processing). 
</span><span style="color: #808080;">///</span><span style="color: #008000;"> If the batch size is greater than the maximum batch size, 
</span><span style="color: #808080;">///</span><span style="color: #008000;"> the method partitions the original batch into multiple batches, 
</span><span style="color: #808080;">///</span><span style="color: #008000;"> each smaller in size than the maximum batch size.
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;/summary&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="queueClient"&gt;</span><span style="color: #008000;">The current QueueClient object.</span><span style="color: #808080;">&lt;/param&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="brokeredMessageEnumerable"&gt;</span><span style="color: #008000;">The collection of brokered messages to send.</span><span style="color: #808080;">&lt;/param&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="trace"&gt;</span><span style="color: #008000;">true to cause a message to be written; otherwise, false.</span><span style="color: #808080;">&lt;/param&gt;</span><span style="color: #808080;">

public static void SendPartitionedBatch(this QueueClient queueClient, IEnumerable<BrokeredMessage> brokeredMessageEnumerable, bool trace = false) { var brokeredMessageList = brokeredMessageEnumerable as IList<BrokeredMessage> ?? brokeredMessageEnumerable.ToList(); if (brokeredMessageEnumerable == null || !brokeredMessageList.Any()) { throw new ArgumentNullException(BrokeredMessageListCannotBeNullOrEmpty); }

  var batchList </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> List</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">BrokeredMessage</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">();
  </span><span style="color: #0000FF;">long</span><span style="color: #000000;"> batchSize </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">;

  </span><span style="color: #0000FF;">foreach</span><span style="color: #000000;"> (var brokeredMessage </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> brokeredMessageList)
  {
    </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> ((batchSize </span><span style="color: #000000;">+</span><span style="color: #000000;"> brokeredMessage.Size) </span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> Constants.MaxBathSizeInBytes)
    {
      </span><span style="color: #008000;">//</span><span style="color: #008000;"> Send current batch</span><span style="color: #008000;">

queueClient.SendBatch(batchList); Trace.WriteLineIf(trace, string.Format(SendPartitionedBatchFormat, batchSize, batchList.Count));

      </span><span style="color: #008000;">//</span><span style="color: #008000;"> Initialize a new batch</span><span style="color: #008000;">

batchList = new List<BrokeredMessage> { brokeredMessage }; batchSize = brokeredMessage.Size; } else { // Add the BrokeredMessage to the current batch batchList.Add(brokeredMessage); batchSize += brokeredMessage.Size; } } // The final batch is sent outside of the loop queueClient.SendBatch(batchList); Trace.WriteLineIf(trace, string.Format(SendPartitionedBatchFormat, batchSize, batchList.Count)); } #endregion } }

The following table contains the code of the EventHubClientExtensions class. Note: all the event data sent in a batch using the EventHubClient.SendBatch or EventHubClient.SendBatchAsync methods need to have the same PartitionKey. In fact, when using one of these methods, all the event data contained in the batch are insersted in the same partition of the event hub by the Event Hub message broker. Hence, they need to share the same value in the PartitionKey property as the latter is used to determine to which partition to send event data.

#region Copyright
//=======================================================================================
// Microsoft Azure Customer Advisory Team  
//
// This sample is supplemental to the technical guidance published on the community
// blog at http://blogs.msdn.com/b/paolos/. 
// 
// Author: Paolo Salvatori
//=======================================================================================
// Copyright © 2015 Microsoft Corporation. All rights reserved.
// 
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF 
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. YOU BEAR THE RISK OF USING IT.
//=======================================================================================
#endregion

#region Using Directives using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using Microsoft.ServiceBus.Messaging; using System.Threading.Tasks; #endregion

namespace Microsoft.AzureCat.ServiceBusExtensions { /// <summary> /// This class contains extensions methods for the EventHubClient class /// </summary> public static class EventHubClientExtensions { #region Private Constants //******************************* // Formats //******************************* private const string EventDataListCannotBeNullOrEmpty = "The eventDataEnumerable parameter cannot be null or empty."; private const string SendPartitionedBatchFormat = "[EventHubClient.SendPartitionedBatch] Batch Sent: BatchSizeInBytes=[{0}] MessageCount=[{1}]"; private const string SendPartitionedBatchAsyncFormat = "[EventHubClient.SendPartitionedBatchAsync] Batch Sent: BatchSizeInBytes=[{0}] MessageCount=[{1}]"; #endregion

</span><span style="color: #0000FF;">#region</span><span style="color: #000000;"> Public Methods</span><span style="color: #000000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;summary&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> Asynchronously sends a batch of event data to the same partition.
</span><span style="color: #808080;">///</span><span style="color: #008000;"> All the event data in the batch need to have the same value in the Partitionkey property.
</span><span style="color: #808080;">///</span><span style="color: #008000;"> If the batch size is greater than the maximum batch size, 
</span><span style="color: #808080;">///</span><span style="color: #008000;"> the method partitions the original batch into multiple batches, 
</span><span style="color: #808080;">///</span><span style="color: #008000;"> each smaller in size than the maximum batch size.
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;/summary&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="eventHubClient"&gt;</span><span style="color: #008000;">The current EventHubClient object.</span><span style="color: #808080;">&lt;/param&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="eventDataEnumerable"&gt;</span><span style="color: #008000;">An IEnumerable object containing event data instances.</span><span style="color: #808080;">&lt;/param&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="trace"&gt;</span><span style="color: #008000;">true to cause a message to be written; otherwise, false.</span><span style="color: #808080;">&lt;/param&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;returns&gt;</span><span style="color: #008000;">The asynchronous operation.</span><span style="color: #808080;">&lt;/returns&gt;</span><span style="color: #808080;">

public async static Task SendPartitionedBatchAsync(this EventHubClient eventHubClient, IEnumerable<EventData> eventDataEnumerable, bool trace = false) { var eventDataList = eventDataEnumerable as IList<EventData> ?? eventDataEnumerable.ToList(); if (eventDataEnumerable == null || !eventDataList.Any()) { throw new ArgumentNullException(EventDataListCannotBeNullOrEmpty); }

  var batchList </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> List</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">EventData</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">();
  </span><span style="color: #0000FF;">long</span><span style="color: #000000;"> batchSize </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">;

  </span><span style="color: #0000FF;">foreach</span><span style="color: #000000;"> (var eventData </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> eventDataList)
  {
    </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> ((batchSize </span><span style="color: #000000;">+</span><span style="color: #000000;"> eventData.SerializedSizeInBytes) </span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> Constants.MaxBathSizeInBytes)
    {
      </span><span style="color: #008000;">//</span><span style="color: #008000;"> Send current batch</span><span style="color: #008000;">

await eventHubClient.SendBatchAsync(batchList); Trace.WriteLineIf(trace, string.Format(SendPartitionedBatchAsyncFormat, batchSize, batchList.Count));

      </span><span style="color: #008000;">//</span><span style="color: #008000;"> Initialize a new batch</span><span style="color: #008000;">

batchList = new List<EventData> { eventData }; batchSize = eventData.SerializedSizeInBytes; } else { // Add the EventData to the current batch batchList.Add(eventData); batchSize += eventData.SerializedSizeInBytes; } } // The final batch is sent outside of the loop await eventHubClient.SendBatchAsync(batchList); Trace.WriteLineIf(trace, string.Format(SendPartitionedBatchAsyncFormat, batchSize, batchList.Count)); }

</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;summary&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> Asynchronously sends a batch of event data to the same partition.
</span><span style="color: #808080;">///</span><span style="color: #008000;"> All the event data in the batch need to have the same value in the Partitionkey property.
</span><span style="color: #808080;">///</span><span style="color: #008000;"> If the batch size is greater than the maximum batch size, 
</span><span style="color: #808080;">///</span><span style="color: #008000;"> the method partitions the original batch into multiple batches, 
</span><span style="color: #808080;">///</span><span style="color: #008000;"> each smaller in size than the maximum batch size.
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;/summary&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="eventHubClient"&gt;</span><span style="color: #008000;">The current EventHubClient object.</span><span style="color: #808080;">&lt;/param&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="eventDataEnumerable"&gt;</span><span style="color: #008000;">An IEnumerable object containing event data instances.</span><span style="color: #808080;">&lt;/param&gt;</span><span style="color: #008000;">
</span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;">&lt;param name="trace"&gt;</span><span style="color: #008000;">true to cause a message to be written; otherwise, false.</span><span style="color: #808080;">&lt;/param&gt;</span><span style="color: #808080;">

public static void SendPartitionedBatch(this EventHubClient eventHubClient, IEnumerable<EventData> eventDataEnumerable, bool trace = false) { var eventDataList = eventDataEnumerable as IList<EventData> ?? eventDataEnumerable.ToList(); if (eventDataEnumerable == null || !eventDataList.Any()) { throw new ArgumentNullException(EventDataListCannotBeNullOrEmpty); }

  var batchList </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> List</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">EventData</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">();
  </span><span style="color: #0000FF;">long</span><span style="color: #000000;"> batchSize </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">;

  </span><span style="color: #0000FF;">foreach</span><span style="color: #000000;"> (var eventData </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> eventDataList)
  {
    </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> ((batchSize </span><span style="color: #000000;">+</span><span style="color: #000000;"> eventData.SerializedSizeInBytes) </span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> Constants.MaxBathSizeInBytes)
    {
      </span><span style="color: #008000;">//</span><span style="color: #008000;"> Send current batch</span><span style="color: #008000;">

eventHubClient.SendBatch(batchList); Trace.WriteLineIf(trace, string.Format(SendPartitionedBatchFormat, batchSize, batchList.Count));

      </span><span style="color: #008000;">//</span><span style="color: #008000;"> Initialize a new batch</span><span style="color: #008000;">

batchList = new List<EventData> { eventData }; batchSize = eventData.SerializedSizeInBytes; } else { // Add the EventData to the current batch batchList.Add(eventData); batchSize += eventData.SerializedSizeInBytes; } } // The final batch is sent outside of the loop eventHubClient.SendBatch(batchList); Trace.WriteLineIf(trace, string.Format(SendPartitionedBatchFormat, batchSize, batchList.Count)); } #endregion } }

TestClient

The following picture shows the TestClient console application that can be used to test each extension method defined by the ServiceBusExtensions library.

TestClient

In the appSettings section of the configuration file you can define the following settings:

  • connectionString: the Service Bus namespace connectionstring.
  • messageSizeInBytes: the size of individual BrokeredMessage and EventData messages.
  • messageCountInBatch: the number of messages in a batch.

Upon start, the client application creates the following entities in the target Service Bus namespace, if they don't already exist.

  • batchtestqueue: this this is the queue used to test the extensions method contained in the QueueClientExtensions and MessageSenderExtensions classes.
  • batchtesttopic: this is the topic used to test the extensions method contained in the TopicClientExtensions class.
  • batcheventhub: this is the event hub used to test the extensions method contained in the EventHubClientExtensions class

Then, the user can use the menu shown by the application to select one of the tests. Each test tries to use the original SendBatchAsync method exposed by each of the essageSender, QueueClient,TopicClient, and EventHubClient classes. If the batch size is greater than the maximum allowed size, the method call will throw a MessageSizeExceededException. The SendPartitionedBatchAsync method instead will split the original batch into one or multiple batches, each smaller than the maximum allowed size, and will send them in the proper order to the target entity.

For your convenience, the following tables includes the code of the TestClient console application.

#region Using Directives
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ServiceBus;
using Microsoft.ServiceBus.Messaging;

#endregion

namespace Microsoft.AzureCat.ServiceBusExtensions.TestClient { /// <summary> /// This class can be used to test the extensions methods defines in the ServiceBusExtensions library. /// </summary> public class Program { #region Private Constants //*************************** // Configuration Parameters //*************************** private const string ConnectionString = "connectionString"; private const string MessageSizeInBytes = "messageSizeInBytes"; private const string MessageCountInBatch = "messageCountInBatch";

</span><span style="color: #008000;">//</span><span style="color: #008000;">***************************
</span><span style="color: #008000;">//</span><span style="color: #008000;"> Entities
</span><span style="color: #008000;">//</span><span style="color: #008000;">***************************</span><span style="color: #008000;">

private const string QueueName = "batchtestqueue"; private const string TopicName = "batchtesttopic"; private const string SubscriptionName = "auditing"; private const string EventHubName = "batchtesteventhub";

</span><span style="color: #008000;">//</span><span style="color: #008000;">***************************
</span><span style="color: #008000;">//</span><span style="color: #008000;"> Default Values
</span><span style="color: #008000;">//</span><span style="color: #008000;">***************************</span><span style="color: #008000;">

private const int DefaultMessageCountInBatch = 100; private const int DefaultMessageSizeInBytes = 16384;

</span><span style="color: #008000;">//</span><span style="color: #008000;">***************************
</span><span style="color: #008000;">//</span><span style="color: #008000;"> Formats
</span><span style="color: #008000;">//</span><span style="color: #008000;">***************************</span><span style="color: #008000;">

private const string ParameterFormat = "{0}: [{1}]"; private const string PressKeyToExit = "Press a key to exit."; private const string MenuChoiceFormat = "Select a numeric key between 1 and {0}"; private const string ConnectionStringCannotBeNull = "The Service Bus connection string has not been defined in the configuration file."; private const string QueueCreatedFormat = "Queue [{0}] successfully created."; private const string TopicCreatedFormat = "Topic [{0}] successfully created."; private const string SubscriptionCreatedFormat = "Subscription [{0}] successfully created."; private const string EventHubCreatedFormat = "Event Hub [{0}] successfully created."; private const string QueueAlreadyExistsFormat = "Queue [{0}] already exists."; private const string TopicAlreadyExistsFormat = "Topic [{0}] already exists."; private const string SubscriptionAlreadyExistsFormat = "Subscription [{0}] already exists."; private const string EventHubAlreadyExistsFormat = "Event Hub [{0}] already exists."; private const string CallingMessageSenderSendBatchAsync = "Calling MessageSender.SendBatchAsync..."; private const string MessageSenderSendBatchAsyncCalled = "MessageSender.SendBatchAsync called."; private const string CallingMessageSenderSendPartitionedBatchAsync = "Calling MessageSender.SendPartitionedBatchAsync..."; private const string MessageSenderSendPartitionedBatchAsyncCalled = "MessageSender.SendPartitionedBatchAsync called."; private const string CallingQueueClientSendBatchAsync = "Calling QueueClient.SendBatchAsync..."; private const string QueueClientSendBatchAsyncCalled = "QueueClient.SendBatchAsync called."; private const string CallingQueueClientSendPartitionedBatchAsync = "Calling QueueClient.SendPartitionedBatchAsync..."; private const string QueueClientSendPartitionedBatchAsyncCalled = "QueueClient.SendPartitionedBatchAsync called."; private const string CallingTopicClientSendBatchAsync = "Calling TopicClient.SendBatchAsync..."; private const string TopicClientSendBatchAsyncCalled = "TopicClient.SendBatchAsync called."; private const string CallingTopicClientSendPartitionedBatchAsync = "Calling TopicClient.SendPartitionedBatchAsync..."; private const string TopicClientSendPartitionedBatchAsyncCalled = "TopicClient.SendPartitionedBatchAsync called."; private const string CallingEventHubClientSendBatchAsync = "Calling EventHubClient.SendBatchAsync..."; private const string EventHubClientSendBatchAsyncCalled = "EventHubClient.SendBatchAsync called."; private const string CallingEventHubClientSendPartitionedBatchAsync = "Calling EventHubClient.SendPartitionedBatchAsync..."; private const string EventHubClientSendPartitionedBatchAsyncCalled = "EventHubClient.SendPartitionedBatchAsync called.";

</span><span style="color: #008000;">//</span><span style="color: #008000;">***************************
</span><span style="color: #008000;">//</span><span style="color: #008000;"> Menu Items
</span><span style="color: #008000;">//</span><span style="color: #008000;">***************************</span><span style="color: #008000;">

private const string MessageSenderSendPartitionedBatchAsyncTest = "MessageSender.SendPartitionedBatchAsync Test"; private const string QueueClientSendPartitionedBatchAsyncTest = "QueueClient.SendPartitionedBatchAsync Test"; private const string TopicClientSendPartitionedBatchAsyncTest = "TopicClient.SendPartitionedBatchAsync Test"; private const string EventHubClientSendPartitionedBatchAsyncTest = "EventHubClient.SendPartitionedBatchAsync Test"; private const string Exit = "Exit"; #endregion

</span><span style="color: #0000FF;">#region</span><span style="color: #000000;"> Private Static Fields</span><span style="color: #000000;">
</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> </span><span style="color: #0000FF;">string</span><span style="color: #000000;"> connectionString;
</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> </span><span style="color: #0000FF;">int</span><span style="color: #000000;"> messageSizeInBytes;
</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> </span><span style="color: #0000FF;">int</span><span style="color: #000000;"> messageCountInBatch;
</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> MessagingFactory messagingFactory;
</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> </span><span style="color: #0000FF;">readonly</span><span style="color: #000000;"> List</span><span style="color: #000000;">&lt;</span><span style="color: #0000FF;">string</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> menuItemList </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> List</span><span style="color: #000000;">&lt;</span><span style="color: #0000FF;">string</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
{
  MessageSenderSendPartitionedBatchAsyncTest ,
  QueueClientSendPartitionedBatchAsyncTest,
  TopicClientSendPartitionedBatchAsyncTest,
  EventHubClientSendPartitionedBatchAsyncTest,
  Exit
}; 
</span><span style="color: #0000FF;">#endregion</span><span style="color: #000000;">

</span><span style="color: #0000FF;">#region</span><span style="color: #000000;"> Main Method</span><span style="color: #000000;">
</span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> Main()
{
  </span><span style="color: #0000FF;">try</span><span style="color: #000000;">
  {
    </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (ReadConfiguration() </span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;"> CreateEntitiesAsync().Result)
    {
      </span><span style="color: #008000;">//</span><span style="color: #008000;"> Add ConsoleTraceListener</span><span style="color: #008000;">

Trace.Listeners.Add(new ConsoleTraceListener());

      </span><span style="color: #008000;">//</span><span style="color: #008000;"> Create MessagingFactory object</span><span style="color: #008000;">

messagingFactory = MessagingFactory.CreateFromConnectionString(connectionString);

      </span><span style="color: #0000FF;">int</span><span style="color: #000000;"> key;
      </span><span style="color: #0000FF;">while</span><span style="color: #000000;"> ((key </span><span style="color: #000000;">=</span><span style="color: #000000;"> ShowMenu()) </span><span style="color: #000000;">!=</span><span style="color: #000000;"> menuItemList.Count </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">)
      {
        </span><span style="color: #0000FF;">switch</span><span style="color: #000000;"> (menuItemList[key])
        {
          </span><span style="color: #0000FF;">case</span><span style="color: #000000;"> MessageSenderSendPartitionedBatchAsyncTest:
            </span><span style="color: #008000;">//</span><span style="color: #008000;"> Test MessageSender.SendPartitionedBatchAsync method</span><span style="color: #008000;">

MessageSenderTest().Wait(); break; case QueueClientSendPartitionedBatchAsyncTest: // Test QueueClient.SendPartitionedBatchAsync method QueueClientTest().Wait(); break; case TopicClientSendPartitionedBatchAsyncTest: // Test TopicClient.SendPartitionedBatchAsync method TopicClientTest().Wait(); break; case EventHubClientSendPartitionedBatchAsyncTest: // Test EventHubClient.SendPartitionedBatchAsync method EventHubClientTest().Wait(); break; case Exit: break; } } } } catch (Exception ex) { PrintException(ex); } PrintMessage(PressKeyToExit); Console.ReadLine(); } #endregion

</span><span style="color: #0000FF;">#region</span><span style="color: #000000;"> Private Static Methods</span><span style="color: #000000;">
</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> async </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> Task MessageSenderTest()
{
  </span><span style="color: #008000;">//</span><span style="color: #008000;"> Create MessageSender object</span><span style="color: #008000;">

var messageSender = await messagingFactory.CreateMessageSenderAsync(QueueName);

  </span><span style="color: #008000;">//</span><span style="color: #008000;"> Test MessageSender.SendBatchAsync: if the batch size is greater than the max batch size
  </span><span style="color: #008000;">//</span><span style="color: #008000;"> the method throws a  MessageSizeExceededException</span><span style="color: #008000;">

try { PrintMessage(CallingMessageSenderSendBatchAsync); await messageSender.SendBatchAsync(CreateBrokeredMessageBatch()); PrintMessage(MessageSenderSendBatchAsyncCalled); } catch (Exception ex) { PrintException(ex); }

  </span><span style="color: #0000FF;">try</span><span style="color: #000000;">
  {
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Send the batch using the SendPartitionedBatchAsync method</span><span style="color: #008000;">

PrintMessage(CallingMessageSenderSendPartitionedBatchAsync); await messageSender.SendPartitionedBatchAsync(CreateBrokeredMessageBatch(), true); PrintMessage(MessageSenderSendPartitionedBatchAsyncCalled); } catch (Exception ex) { PrintException(ex); } }

</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> async </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> Task QueueClientTest()
{
  </span><span style="color: #008000;">//</span><span style="color: #008000;"> Create QueueClient object</span><span style="color: #008000;">

var queueClient = messagingFactory.CreateQueueClient(QueueName);

  </span><span style="color: #008000;">//</span><span style="color: #008000;"> Test QueueClient.SendBatchAsync: if the batch size is greater than the max batch size
  </span><span style="color: #008000;">//</span><span style="color: #008000;"> the method throws a  MessageSizeExceededException</span><span style="color: #008000;">

try { PrintMessage(CallingQueueClientSendBatchAsync); await queueClient.SendBatchAsync(CreateBrokeredMessageBatch()); PrintMessage(QueueClientSendBatchAsyncCalled); } catch (Exception ex) { PrintException(ex); }

  </span><span style="color: #0000FF;">try</span><span style="color: #000000;">
  {
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Send the batch using the SendPartitionedBatchAsync method</span><span style="color: #008000;">

PrintMessage(CallingQueueClientSendPartitionedBatchAsync); await queueClient.SendPartitionedBatchAsync(CreateBrokeredMessageBatch(), true); PrintMessage(QueueClientSendPartitionedBatchAsyncCalled); } catch (Exception ex) { PrintException(ex); } }

</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> async </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> Task TopicClientTest()
{
  </span><span style="color: #008000;">//</span><span style="color: #008000;"> Create TopicClient object</span><span style="color: #008000;">

var topicClient = messagingFactory.CreateTopicClient(TopicName);

  </span><span style="color: #008000;">//</span><span style="color: #008000;"> Test TopicClient.SendBatchAsync: if the batch size is greater than the max batch size
  </span><span style="color: #008000;">//</span><span style="color: #008000;"> the method throws a  MessageSizeExceededException</span><span style="color: #008000;">

try { PrintMessage(CallingTopicClientSendBatchAsync); await topicClient.SendBatchAsync(CreateBrokeredMessageBatch()); PrintMessage(TopicClientSendBatchAsyncCalled); } catch (Exception ex) { PrintException(ex); }

  </span><span style="color: #0000FF;">try</span><span style="color: #000000;">
  {
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Send the batch using the SendPartitionedBatchAsync method</span><span style="color: #008000;">

PrintMessage(CallingTopicClientSendPartitionedBatchAsync); await topicClient.SendPartitionedBatchAsync(CreateBrokeredMessageBatch(), true); PrintMessage(TopicClientSendPartitionedBatchAsyncCalled); } catch (Exception ex) { PrintException(ex); } }

</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> async </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> Task EventHubClientTest()
{
  </span><span style="color: #008000;">//</span><span style="color: #008000;"> Create EventHubClient object</span><span style="color: #008000;">

var eventHubClient = EventHubClient.CreateFromConnectionString(connectionString, EventHubName);

  </span><span style="color: #008000;">//</span><span style="color: #008000;"> Test EventHubClient.SendBatchAsync: if the batch size is greater than the max batch size
  </span><span style="color: #008000;">//</span><span style="color: #008000;"> the method throws a  MessageSizeExceededException</span><span style="color: #008000;">

try { PrintMessage(CallingEventHubClientSendBatchAsync); await eventHubClient.SendBatchAsync(CreateEventDataBatch()); PrintMessage(EventHubClientSendBatchAsyncCalled); } catch (Exception ex) { PrintException(ex); }

  </span><span style="color: #0000FF;">try</span><span style="color: #000000;">
  {
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Send the batch using the SendPartitionedBatchAsync method</span><span style="color: #008000;">

PrintMessage(CallingEventHubClientSendPartitionedBatchAsync); await eventHubClient.SendPartitionedBatchAsync(CreateEventDataBatch(), true); PrintMessage(EventHubClientSendPartitionedBatchAsyncCalled); } catch (Exception ex) { PrintException(ex); } }

</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> IEnumerable</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">BrokeredMessage</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> CreateBrokeredMessageBatch()
{
  var messageList </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> List</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">BrokeredMessage</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">();
  </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> (var i </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">; i </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> messageCountInBatch; i</span><span style="color: #000000;">++</span><span style="color: #000000;">)
  {
    messageList.Add(</span><span style="color: #0000FF;">new</span><span style="color: #000000;"> BrokeredMessage(Encoding.UTF8.GetBytes(</span><span style="color: #0000FF;">new</span><span style="color: #000000;"> </span><span style="color: #0000FF;">string</span><span style="color: #000000;">(</span><span style="color: #800000;">'</span><span style="color: #800000;">A</span><span style="color: #800000;">'</span><span style="color: #000000;">, messageSizeInBytes))));
  }
  </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> messageList;
}

</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> IEnumerable</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">EventData</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> CreateEventDataBatch()
{
  var messageList </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> List</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">EventData</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">();
  </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> (var i </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">; i </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> messageCountInBatch; i</span><span style="color: #000000;">++</span><span style="color: #000000;">)
  {
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Note: the partition key in this sample is null.
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> it's mandatory that all event data in a batch have the same PartitionKey</span><span style="color: #008000;">

messageList.Add(new EventData(Encoding.UTF8.GetBytes(new string('A', messageSizeInBytes)))); } return messageList; }

</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> async </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> Task</span><span style="color: #000000;">&lt;</span><span style="color: #0000FF;">bool</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> CreateEntitiesAsync()
{
  </span><span style="color: #0000FF;">try</span><span style="color: #000000;">
  {
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Create NamespaceManeger object</span><span style="color: #008000;">

var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);

    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Create test queue</span><span style="color: #008000;">

if (!await namespaceManager.QueueExistsAsync(QueueName)) { await namespaceManager.CreateQueueAsync(new QueueDescription(QueueName) { EnableBatchedOperations = true, EnableExpress = true, EnablePartitioning = true, EnableDeadLetteringOnMessageExpiration = true }); PrintMessage(string.Format(QueueCreatedFormat, QueueName)); } else { PrintMessage(string.Format(QueueAlreadyExistsFormat, QueueName)); }

    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Create test topic</span><span style="color: #008000;">

if (!await namespaceManager.TopicExistsAsync(TopicName)) { await namespaceManager.CreateTopicAsync(new TopicDescription(TopicName) { EnableBatchedOperations = true, EnableExpress = true, EnablePartitioning = true, }); PrintMessage(string.Format(TopicCreatedFormat, TopicName)); } else { PrintMessage(string.Format(TopicAlreadyExistsFormat, TopicName)); }

    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Create test subscription</span><span style="color: #008000;">

if (!await namespaceManager.SubscriptionExistsAsync(TopicName, SubscriptionName)) { await namespaceManager.CreateSubscriptionAsync(new SubscriptionDescription(TopicName, SubscriptionName) { EnableBatchedOperations = true }, new RuleDescription(new TrueFilter())); PrintMessage(string.Format(SubscriptionCreatedFormat, SubscriptionName)); } else { PrintMessage(string.Format(SubscriptionAlreadyExistsFormat, SubscriptionName)); }

    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Create test event hub</span><span style="color: #008000;">

if (!await namespaceManager.EventHubExistsAsync(EventHubName)) { await namespaceManager.CreateEventHubAsync(new EventHubDescription(EventHubName) { PartitionCount = 16, MessageRetentionInDays = 1 }); PrintMessage(string.Format(EventHubCreatedFormat, EventHubName)); } else { PrintMessage(string.Format(EventHubAlreadyExistsFormat, EventHubName)); } } catch (Exception ex) { PrintException(ex); return false; } return true; }

</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> </span><span style="color: #0000FF;">int</span><span style="color: #000000;"> ShowMenu()
{
  </span><span style="color: #008000;">//</span><span style="color: #008000;"> Print Menu Header</span><span style="color: #008000;">

Console.ForegroundColor = ConsoleColor.Green; Console.Write("["); Console.ForegroundColor = ConsoleColor.Yellow; Console.Write("Menu"); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("]"); Console.ResetColor();

  </span><span style="color: #008000;">//</span><span style="color: #008000;"> Print Menu Items</span><span style="color: #008000;">

for (var i = 0; i < menuItemList.Count; i++) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("["); Console.ForegroundColor = ConsoleColor.Yellow; Console.Write("{0}", i + 1); Console.ForegroundColor = ConsoleColor.Green; Console.Write("]"); Console.ResetColor(); Console.Write(": "); Console.WriteLine(menuItemList[i]); Console.ResetColor(); }

  </span><span style="color: #008000;">//</span><span style="color: #008000;"> Select an option</span><span style="color: #008000;">

Console.ForegroundColor = ConsoleColor.Green; Console.Write("["); Console.ForegroundColor = ConsoleColor.Yellow; Console.Write(MenuChoiceFormat, menuItemList.Count); Console.ForegroundColor = ConsoleColor.Green; Console.Write("]"); Console.ResetColor(); Console.Write(": ");

  var key </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">'</span><span style="color: #800000;">a</span><span style="color: #800000;">'</span><span style="color: #000000;">;
  </span><span style="color: #0000FF;">while</span><span style="color: #000000;"> (key </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> </span><span style="color: #800000;">'</span><span style="color: #800000;">1</span><span style="color: #800000;">'</span><span style="color: #000000;"> </span><span style="color: #000000;">||</span><span style="color: #000000;"> key </span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> </span><span style="color: #800000;">'</span><span style="color: #800000;">9</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  {
    key </span><span style="color: #000000;">=</span><span style="color: #000000;"> Console.ReadKey(</span><span style="color: #0000FF;">true</span><span style="color: #000000;">).KeyChar;
  }
  Console.WriteLine();
  </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> key </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800000;">'</span><span style="color: #800000;">1</span><span style="color: #800000;">'</span><span style="color: #000000;">;
}

</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> </span><span style="color: #0000FF;">bool</span><span style="color: #000000;"> ReadConfiguration()
{
  </span><span style="color: #0000FF;">try</span><span style="color: #000000;">
  {
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Set window size</span><span style="color: #008000;">

Console.SetWindowSize(120, 40);

    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Read connectionString setting</span><span style="color: #008000;">

connectionString = ConfigurationManager.AppSettings[ConnectionString]; if (string.IsNullOrWhiteSpace(connectionString)) { throw new ArgumentException(ConnectionStringCannotBeNull); } PrintMessage(string.Format(ParameterFormat, ConnectionString, connectionString));

    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Read messageSizeInBytes setting</span><span style="color: #008000;">

int value; var setting = ConfigurationManager.AppSettings[MessageSizeInBytes]; messageSizeInBytes = int.TryParse(setting, out value) ? value : DefaultMessageSizeInBytes; PrintMessage(string.Format(ParameterFormat, MessageSizeInBytes, messageSizeInBytes));

    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Read messageCountInBatch setting</span><span style="color: #008000;">

setting = ConfigurationManager.AppSettings[MessageCountInBatch]; messageCountInBatch = int.TryParse(setting, out value) ? value : DefaultMessageCountInBatch; PrintMessage(string.Format(ParameterFormat, MessageCountInBatch, messageCountInBatch)); return true; } catch (Exception ex) { PrintException(ex); } return false; }

</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> PrintMessage(</span><span style="color: #0000FF;">string</span><span style="color: #000000;"> message, [CallerMemberName] </span><span style="color: #0000FF;">string</span><span style="color: #000000;"> memberName </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">""</span><span style="color: #000000;">)
{
  </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (</span><span style="color: #0000FF;">string</span><span style="color: #000000;">.IsNullOrWhiteSpace(message) </span><span style="color: #000000;">||</span><span style="color: #000000;"> </span><span style="color: #0000FF;">string</span><span style="color: #000000;">.IsNullOrWhiteSpace(memberName))
  {
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;">;
  }
  Console.ForegroundColor </span><span style="color: #000000;">=</span><span style="color: #000000;"> ConsoleColor.Green;
  Console.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;">[</span><span style="color: #800000;">"</span><span style="color: #000000;">);
  Console.ForegroundColor </span><span style="color: #000000;">=</span><span style="color: #000000;"> ConsoleColor.Yellow;
  Console.Write(memberName);
  Console.ForegroundColor </span><span style="color: #000000;">=</span><span style="color: #000000;"> ConsoleColor.Green;
  Console.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;">]</span><span style="color: #800000;">"</span><span style="color: #000000;">);
  Console.ResetColor();
  Console.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;">: </span><span style="color: #800000;">"</span><span style="color: #000000;">);
  Console.WriteLine(message);
}

</span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> PrintException(Exception ex,
                   [CallerFilePath] </span><span style="color: #0000FF;">string</span><span style="color: #000000;"> sourceFilePath </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">""</span><span style="color: #000000;">,
                   [CallerMemberName] </span><span style="color: #0000FF;">string</span><span style="color: #000000;"> memberName </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">""</span><span style="color: #000000;">,
                   [CallerLineNumber] </span><span style="color: #0000FF;">int</span><span style="color: #000000;"> sourceLineNumber </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">)
{
  Console.ForegroundColor </span><span style="color: #000000;">=</span><span style="color: #000000;"> ConsoleColor.Green;
  Console.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;">[</span><span style="color: #800000;">"</span><span style="color: #000000;">);
  Console.ForegroundColor </span><span style="color: #000000;">=</span><span style="color: #000000;"> ConsoleColor.Yellow;
  </span><span style="color: #0000FF;">string</span><span style="color: #000000;"> fileName </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">null</span><span style="color: #000000;">;
  </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (File.Exists(sourceFilePath))
  {
    var file </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> FileInfo(sourceFilePath);
    fileName </span><span style="color: #000000;">=</span><span style="color: #000000;"> file.Name;
  }
  Console.Write(</span><span style="color: #0000FF;">string</span><span style="color: #000000;">.IsNullOrWhiteSpace(fileName) </span><span style="color: #000000;">?</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">Unknown</span><span style="color: #800000;">"</span><span style="color: #000000;"> : fileName);
  Console.ForegroundColor </span><span style="color: #000000;">=</span><span style="color: #000000;"> ConsoleColor.Green;
  Console.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;">:</span><span style="color: #800000;">"</span><span style="color: #000000;">);
  Console.ForegroundColor </span><span style="color: #000000;">=</span><span style="color: #000000;"> ConsoleColor.Yellow;
  Console.Write(</span><span style="color: #0000FF;">string</span><span style="color: #000000;">.IsNullOrWhiteSpace(memberName) </span><span style="color: #000000;">?</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">Unknown</span><span style="color: #800000;">"</span><span style="color: #000000;"> : memberName);
  Console.ForegroundColor </span><span style="color: #000000;">=</span><span style="color: #000000;"> ConsoleColor.Green;
  Console.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;">:</span><span style="color: #800000;">"</span><span style="color: #000000;">);
  Console.ForegroundColor </span><span style="color: #000000;">=</span><span style="color: #000000;"> ConsoleColor.Yellow;
  Console.Write(sourceLineNumber.ToString(CultureInfo.InvariantCulture));
  Console.ForegroundColor </span><span style="color: #000000;">=</span><span style="color: #000000;"> ConsoleColor.Green;
  Console.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;">]</span><span style="color: #800000;">"</span><span style="color: #000000;">);
  Console.ResetColor();
  Console.Write(</span><span style="color: #800000;">"</span><span style="color: #800000;">: </span><span style="color: #800000;">"</span><span style="color: #000000;">);
  Console.WriteLine(ex </span><span style="color: #000000;">!=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">null</span><span style="color: #000000;"> </span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;"> </span><span style="color: #000000;">!</span><span style="color: #0000FF;">string</span><span style="color: #000000;">.IsNullOrWhiteSpace(ex.Message) </span><span style="color: #000000;">?</span><span style="color: #000000;"> ex.Message : </span><span style="color: #800000;">"</span><span style="color: #800000;">An error occurred.</span><span style="color: #800000;">"</span><span style="color: #000000;">);
  var aggregateException </span><span style="color: #000000;">=</span><span style="color: #000000;"> ex </span><span style="color: #0000FF;">as</span><span style="color: #000000;"> AggregateException;
  </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (aggregateException </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #0000FF;">null</span><span style="color: #000000;">)
  {
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;">;
  }
  </span><span style="color: #0000FF;">foreach</span><span style="color: #000000;"> (var exception </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> aggregateException.InnerExceptions)
  {
    PrintException(exception);
  }
}
</span><span style="color: #0000FF;">#endregion</span><span style="color: #000000;">

} }