static async Task Main()
    {
        Console.Title = "Samples.SqlServer.Native.AuditConsumer";
        Console.WriteLine("Press any key to exit");

        await CreateAuditQueue().ConfigureAwait(false);

        #region MessageConsumingLoop

        async Task Callback(SqlTransaction transaction, IncomingMessage message, CancellationToken cancellation)
        {
            using (var reader = new StreamReader(message.Body))
            {
                var bodyText = await reader.ReadToEndAsync().ConfigureAwait(false);

                Console.WriteLine($"Message received in audit queue:\r\n{bodyText}");
            }
        }

        void ErrorCallback(Exception exception)
        {
            Environment.FailFast("Message consuming loop failed", exception);
        }

        Task <SqlTransaction> TransactionBuilder(CancellationToken cancellation)
        {
            return(ConnectionHelpers.BeginTransaction(SqlHelper.ConnectionString, cancellation));
        }

        var consumingLoop = new MessageConsumingLoop(
            table: "audit",
            delay: TimeSpan.FromSeconds(1),
            transactionBuilder: TransactionBuilder,
            callback: Callback,
            errorCallback: ErrorCallback);
        consumingLoop.Start();

        Console.ReadKey();

        await consumingLoop.Stop()
        .ConfigureAwait(false);

        #endregion
    }
    async Task ConsumeLoop()
    {
        #region ConsumeLoop

        async Task Callback(SqlTransaction transaction, IncomingMessage message, CancellationToken cancellation)
        {
            using (var reader = new StreamReader(message.Body))
            {
                var bodyText = await reader.ReadToEndAsync()
                               .ConfigureAwait(false);

                Console.WriteLine($"Reply received:\r\n{bodyText}");
            }
        }

        Task <SqlTransaction> TransactionBuilder(CancellationToken cancellation)
        {
            return(ConnectionHelpers.BeginTransaction(connectionString, cancellation));
        }

        void ErrorCallback(Exception exception)
        {
            Environment.FailFast("Message consuming loop failed", exception);
        }

        // start consuming
        var consumingLoop = new MessageConsumingLoop(
            table: "endpointTable",
            delay: TimeSpan.FromSeconds(1),
            transactionBuilder: TransactionBuilder,
            callback: Callback,
            errorCallback: ErrorCallback);
        consumingLoop.Start();

        // stop consuming
        await consumingLoop.Stop()
        .ConfigureAwait(false);

        #endregion
    }
    static async Task Main()
    {
        Console.Title = "Samples.SqlServer.Native.NativeEndpoint";
        Console.WriteLine("Press s to send a message that will succeed");
        Console.WriteLine("Press f to send a message that will fail");
        Console.WriteLine("Press any key to exit");

        await CreateQueue().ConfigureAwait(false);

        #region receive

        Task Callback(SqlTransaction sqlTransaction, IncomingBytesMessage message, CancellationToken cancellation)
        {
            var bodyText = Encoding.UTF8.GetString(message.Body);

            Console.WriteLine($"Reply received:\r\n{bodyText}");
            return(Task.CompletedTask);
        }

        void ErrorCallback(Exception exception)
        {
            Environment.FailFast("Message consuming loop failed", exception);
        }

        Task <SqlTransaction> TransactionBuilder(CancellationToken cancellation)
        {
            return(ConnectionHelpers.BeginTransaction(SqlHelper.ConnectionString, cancellation));
        }

        var messageConsumingLoop = new MessageConsumingLoop(
            table: "NativeEndpoint",
            delay: TimeSpan.FromSeconds(1),
            transactionBuilder: TransactionBuilder,
            callback: Callback,
            errorCallback: ErrorCallback);
        messageConsumingLoop.Start();

        #endregion

        while (true)
        {
            var key = Console.ReadKey();
            Console.WriteLine();

            if (key.Key == ConsoleKey.S)
            {
                await SendMessageThatWillSucceed()
                .ConfigureAwait(false);

                continue;
            }

            if (key.Key == ConsoleKey.F)
            {
                await SendMessageThatWillFail()
                .ConfigureAwait(false);

                continue;
            }

            break;
        }

        await messageConsumingLoop.Stop()
        .ConfigureAwait(false);
    }