static void Main(string[] args) {
			var broker = new SqlServerServiceBroker("Server=.;Integrated Security=SSPI;Initial Catalog=WorkWork");
/*
			var workQueue = broker.OpenChannel<string>();
			Task.Factory.StartNew(() => {
				for(var i = 0; i != 10; ++i) {
					workQueue.Send(i.ToString());
					Thread.Sleep(250);
				}
				workQueue.Send("Bye.");
			}, TaskCreationOptions.LongRunning);

			for(var done = false; !done;) {
				workQueue.TryReceive(x => {
					if(x == "Bye.")
						done = true;
					Console.WriteLine(x);
				});
			}
*/
			var q2 = broker.OpenChannel<Message>();
			for(;;) 
				q2.Send(Message.NewMessage(Console.ReadLine()));

		}
        public async Task BeginConversationTimerAsync_ArgumentsCannotBeNull()
        {
            // Arrange
            var provider = new SqlServerServiceBroker(connection);

            // Act
            Func<Task> call = async () => await provider.BeginConversationTimerAsync(null);

            // Assert
            await Assert.ThrowsAsync<ArgumentNullException>("arguments", call);
        }
        public async Task BeginTransactionAsync_ThrowsInvalidOperationException_WhileTransactionActive()
        {
            // Arrange
            var provider = new SqlServerServiceBroker(connection);
            var transaction = default(IServiceBrokerTransaction);

            // Act
            Func<Task> call1 = async () =>
            {
                try
                {
                    provider.UseTransaction(connection.BeginTransaction());
                    transaction = await provider.BeginTransactionAsync();
                }
                finally
                {
                    provider.UseTransaction(null);
                }
            };

            Func<Task> call2 = async () =>
            {
                try
                {
                    transaction = await provider.BeginTransactionAsync();
                    transaction = await provider.BeginTransactionAsync();
                }
                finally
                {
                    provider.UseTransaction(null);
                }
            };

            // Assert
            await Assert.ThrowsAsync<InvalidOperationException>(call1);
            Assert.Null(transaction);
            await Assert.ThrowsAsync<InvalidOperationException>(call2);
            Assert.NotNull(transaction);
        }
        public async Task BeginDialogAsync_RespectsBrokerInstanceCurrentDatabase()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var arguments = new BeginDialogArguments("InitiatorService", "TargetService")
            {
                BrokerInstance = BrokerInstance.CurrentDatabase,
            };

            // Act
            var conversationHandle = await provider.BeginDialogAsync(arguments);
            var sql = @"
SELECT CAST(e.far_broker_instance AS uniqueidentifier) AS [actual],
       (SELECT service_broker_guid FROM sys.databases WHERE database_id = DB_ID()) AS [expected]
FROM sys.conversation_endpoints e
WHERE conversation_handle = @handle
";
            var results = await connection.QueryAsync(sql, new { handle = conversationHandle.Value });
            var conversation = results.Single();

            // Assert
            Assert.Equal(conversation.expected, conversation.actual);
        }
        public async Task BeginConversationTimerAsync_Succeeds()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var handle = await BeginDialogAsync();
            var provider = new SqlServerServiceBroker(connection);
            var arguments = new BeginConversationTimerArguments(handle, 600);

            // Act
            await provider.BeginConversationTimerAsync(arguments);
            var sql = @"SELECT * FROM sys.conversation_endpoints WHERE conversation_handle = @handle";
            var results = await connection.QueryAsync(sql, new { handle });
            var scheduledTime = (DateTime)results.Single().dialog_timer;

            // Assert
            Assert.True(scheduledTime > DateTime.Now);
        }
        public async Task SendAsync_RespectsMessageType()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await provider.BeginDialogAsync(
                new BeginDialogArguments("InitiatorService", "TargetService")
                {
                    ContractName = "TestContract",
                });

            // Act
            await provider.SendAsync(new SendArguments(handle)
            {
                MessageTypeName = "TestMessageType",
            });
            var received = await connection.QueryAsync("SELECT * FROM [TargetQueue] WITH (NOLOCK)");

            // Assert
            Assert.Equal("TestMessageType", received.Single().message_type_name);
        }
        public async Task ReceiveAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync();
            await connection.ExecuteAsync("SEND ON CONVERSATION @handle;", new { handle });

            // Act
            var transaction = await provider.BeginTransactionAsync();
            var beforeRollback = await provider.ReceiveAsync(new ReceiveArguments("TargetQueue"));
            transaction.Rollback();
            var afterRollback = await provider.ReceiveAsync(new ReceiveArguments("TargetQueue"));

            // Assert
            Assert.NotEmpty(beforeRollback);
            Assert.NotEmpty(afterRollback);
        }
        public async Task ReceiveAsync_RespectsWaitFor()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync();

            // Act
            var receive = provider.ReceiveAsync(new ReceiveArguments("TargetQueue")
            {
                WaitFor = MillisecondTimeout.Unlimited,
            });
            Thread.Sleep(1000);

            // Assert
            Assert.False(receive.IsCompleted);
        }
        public async Task ReceiveAsync_RespectsQueue()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync();
            await connection.ExecuteAsync("SEND ON CONVERSATION @handle;", new { handle });

            // Act
            var receive = await provider.ReceiveAsync(new ReceiveArguments("TargetQueue")
            {
            });

            // Assert
            Assert.True(receive.Any());
        }
        public async Task BeginDialogAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var arguments = new BeginDialogArguments("InitiatorService", "TargetService");
            var handle = default(ConversationHandle);

            // Act
            using (var transaction = await provider.BeginTransactionAsync())
            {
                handle = await provider.BeginDialogAsync(arguments);
                transaction.Rollback();
            }

            var sql = @"SELECT * FROM sys.conversation_endpoints WHERE conversation_handle = @handle";
            var results = await connection.QueryAsync(sql, new { handle = handle.Value });

            // Assert
            Assert.Empty(results);
        }
        public async Task BeginDialogAsync_RespectsEncryptionOn()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var arguments = new BeginDialogArguments("InitiatorService", "TargetService")
            {
                Encryption = true,
            };

            // Act
            var conversationHandle = await provider.BeginDialogAsync(arguments);
            var sql = @"
SEND ON CONVERSATION @handle;
SELECT GET_TRANSMISSION_STATUS(@handle) AS [status]";
            var results = await connection.QueryAsync(sql, new { handle = conversationHandle.Value });
            var status = results.Single().status;

            // Assert
            Assert.StartsWith("The session keys", status);
        }
        public async Task BeginDialogAsync_RespectsEncryptionOff()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var arguments = new BeginDialogArguments("InitiatorService", "TargetService")
            {
                Encryption = true,
            };

            // Act
            var conversationHandle = await provider.BeginDialogAsync(arguments);
            var sql = @"
SEND ON CONVERSATION @handle;
SELECT * FROM sys.conversation_endpoints WHERE conversation_handle = @handle";
            var results = await connection.QueryAsync(sql, new { handle = conversationHandle.Value });
            var conversation = results.Single();

            // Assert
            Assert.Equal("CO", conversation.state);
            Assert.Equal(Guid.Empty, conversation.outbound_session_key_identifier);
            Assert.Equal(Guid.Empty, conversation.inbound_session_key_identifier);
        }
        public async Task BeginDialogAsync_RespectsRelatedConversationHandlesAndGroupIds()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var group = Guid.NewGuid();
            var arguments = new BeginDialogArguments("InitiatorService", "TargetService")
            {
                Related = (ConversationGroupId)group
            };

            // Act
            var conversationHandle = await provider.BeginDialogAsync(arguments);
            arguments.Related = conversationHandle;
            conversationHandle = await provider.BeginDialogAsync(arguments);
            var sql = @"
SELECT e.conversation_group_id
FROM sys.conversation_endpoints e
WHERE conversation_handle = @handle
";
            var results = await connection.QueryAsync(sql, new { handle = conversationHandle.Value });
            var conversation = results.Single();

            // Assert
            Assert.Equal(group, conversation.conversation_group_id);
        }
        public async Task BeginDialogAsync_RespectsLifeTime()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var arguments = new BeginDialogArguments("InitiatorService", "TargetService")
            {
                Lifetime = TimeSpan.FromHours(23),
            };

            // Act
            var conversationHandle = await provider.BeginDialogAsync(arguments);
            var sql = @"
SELECT e.lifetime
FROM sys.conversation_endpoints e
WHERE conversation_handle = @handle
";
            var results = await connection.QueryAsync(sql, new { handle = conversationHandle.Value });
            var conversation = results.Single();

            // Assert
            Assert.True(conversation.lifetime < DateTime.Now.AddDays(1).ToUniversalTime());
        }
        public async Task BeginDialogAsync_RespectsContract()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var arguments = new BeginDialogArguments("InitiatorService", "TargetService")
            {
                ContractName = "TestContract",
            };

            // Act
            var conversationHandle = await provider.BeginDialogAsync(arguments);
            var sql = @"
SELECT c.name
FROM sys.conversation_endpoints e
JOIN sys.service_contracts c
    ON c.service_contract_id = e.service_contract_id
WHERE conversation_handle = @handle
";
            var results = await connection.QueryAsync(sql, new { handle = conversationHandle.Value });
            var contract = results.Single();

            // Assert
            Assert.Equal("TestContract", contract.name);
        }
        public async Task MoveConversationAsync_Succeeds()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync();
            var sql = @"SELECT [conversation_group_id] FROM sys.conversation_endpoints WHERE conversation_handle = @handle";
            var newGroupId = await connection.ExecuteScalarAsync<Guid>(sql, new { handle });
            handle = await BeginDialogAsync();

            // Act
            await provider.MoveConversationAsync(new MoveConversationArguments(handle, newGroupId));
            var actualGroupId = await connection.ExecuteScalarAsync<Guid>(sql, new { handle });

            // Assert
            Assert.Equal(newGroupId, actualGroupId);
        }
        public async Task MoveConversationAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle1 = await BeginDialogAsync();
            var handle2 = await BeginDialogAsync();
            var sql = @"SELECT [conversation_group_id] FROM sys.conversation_endpoints WHERE conversation_handle = @handle";
            var group1 = await connection.ExecuteScalarAsync<Guid>(sql, new { handle = handle1 });
            var group2 = await connection.ExecuteScalarAsync<Guid>(sql, new { handle = handle2 });

            // Act
            using (var transaction = await provider.BeginTransactionAsync())
            {
                await provider.MoveConversationAsync(new MoveConversationArguments(handle1, group2));
                transaction.Rollback();
            }

            var afterRollback = await connection.ExecuteScalarAsync<Guid>(sql, new { handle = handle1 });

            // Assert
            Assert.Equal(group1, afterRollback);
        }
        public async Task EndConversationAsync_Succeeds()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync();

            // Act
            await provider.EndConversationAsync(new EndConversationArguments(handle));
            var sql = @"SELECT [state] FROM sys.conversation_endpoints WHERE conversation_handle = @handle";
            var results = await connection.QueryAsync(sql, new { handle });

            // Assert
            Assert.Empty(results);
        }
        public async Task ReceiveAsync_RespectsTop()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync();
            await connection.ExecuteAsync("SEND ON CONVERSATION @handle;", new { handle });
            await connection.ExecuteAsync("SEND ON CONVERSATION @handle;", new { handle });

            // Act
            var receive = await provider.ReceiveAsync(new ReceiveArguments("TargetQueue")
            {
                Top = 1,
                WaitFor = TimeSpan.FromSeconds(5),
            });

            // Assert
            Assert.Equal(1, receive.Count());
        }
        public async Task EndConversationAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync();

            // Act
            using (var transaction = await provider.BeginTransactionAsync())
            {
                await provider.EndConversationAsync(new EndConversationArguments(handle));
                transaction.Rollback();
            }

            var sql = @"SELECT [state] FROM sys.conversation_endpoints WHERE conversation_handle = @handle";
            var results = await connection.QueryAsync(sql, new { handle });

            // Assert
            Assert.NotEmpty(results);
        }
        public async Task ReceiveAsync_RespectsPredicate_ConversationGroupId()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle1 = await BeginDialogAsync();
            await connection.ExecuteAsync("SEND ON CONVERSATION @handle1;", new { handle1 });
            var handle2 = await BeginDialogAsync();
            await connection.ExecuteAsync("SEND ON CONVERSATION @handle2;", new { handle2 });
            var groups = await connection.QueryAsync(
                "SELECT conversation_group_id FROM [TargetQueue] WITH (NOLOCK)");
            var group = groups.Last().conversation_group_id;

            // Act
            var receive = await provider.ReceiveAsync(new ReceiveArguments("TargetQueue")
            {
                Predicate = (ConversationGroupId)group,
            });

            // Assert
            Assert.Equal(group, receive.Single().ConversationGroupId.Value);
        }
        public async Task GetConversationGroupAsync_RespectsQueue()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync();
            await connection.ExecuteAsync("SEND ON CONVERSATION @handle;", new { handle });

            // Act
            var groupId = await provider.GetConversationGroupAsync(new GetConversationGroupArguments("TargetQueue")
            {
            });

            // Assert
            Assert.True(groupId.HasValue);
            Assert.NotEqual(Guid.Empty, groupId.GetValueOrDefault().Value);
        }
        public async Task ReceiveAsync_DecodesMessageBodyAsUnicode()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync();
            await connection.ExecuteAsync("SEND ON CONVERSATION @handle (N'Hello');", new { handle });
            await connection.ExecuteAsync("SEND ON CONVERSATION @handle ('Hello');", new { handle });

            // Act
            var receive = await provider.ReceiveAsync(new ReceiveArguments("TargetQueue")
            {
            });

            // Assert
            Assert.Equal("Hello", receive.First().Body);
            Assert.NotEqual("Hello", receive.Last().Body);
        }
        public async Task GetConversationGroupAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider1 = new SqlServerServiceBroker(connection);
            var provider2 = new SqlServerServiceBroker(new SqlConnection(connection.ConnectionString));
            var handle = await BeginDialogAsync();
            IEnumerable<ReceivedMessage> beforeRollback;
            IEnumerable<ReceivedMessage> afterRollback;
            await connection.ExecuteAsync("SEND ON CONVERSATION @handle;", new { handle });

            // Act
            using (var transaction = await provider1.BeginTransactionAsync())
            {
                var arguments = new GetConversationGroupArguments("TargetQueue");
                var groupId = await provider1.GetConversationGroupAsync(arguments);
                var receiveArgs = new ReceiveArguments("TargetQueue")
                {
                    Predicate = groupId.Value,
                    WaitFor = TimeSpan.FromSeconds(1),
                };

                beforeRollback = await provider2.ReceiveAsync(receiveArgs);
                transaction.Rollback();
                afterRollback = await provider2.ReceiveAsync(receiveArgs);
            }

            // Assert
            Assert.Empty(beforeRollback);
            Assert.NotEmpty(afterRollback);
        }
        public async Task SendAsync_RespectsMultipleConversationHandles()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle1 = await BeginDialogAsync();
            var handle2 = await BeginDialogAsync();

            // Act
            await provider.SendAsync(new SendArguments(handle1, handle2));
            var received = await connection.QueryAsync("SELECT * FROM [TargetQueue] WITH (NOLOCK)");

            // Assert
            Assert.Equal(2, received.Count());
        }
        public async Task GetTransmissionStatusAsync_ArgumentsCannotBeNull()
        {
            // Arrange
            var provider = new SqlServerServiceBroker(connection);

            // Act
            Func<Task> call = async () => await provider.GetTransmissionStatusAsync(null);

            // Assert
            await Assert.ThrowsAsync<ArgumentNullException>("arguments", call);
        }
        public async Task SendAsync_RespectsMessageBody()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync();
            var body = "Quoth the Sandler, Barrymore";

            // Act
            await provider.SendAsync(new SendArguments(handle)
            {
                MessageBody = body,
            });
            var received = await connection.QueryAsync("SELECT CAST(message_body AS nvarchar(max)) AS message_body FROM [TargetQueue] WITH (NOLOCK)");

            // Assert
            Assert.Equal(body, received.Single().message_body);
        }
        public async Task GetTransmissionStatusAsync_Succeeds()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync(encryption: true);
            await connection.ExecuteAsync("SEND ON CONVERSATION @handle;", new { handle });

            // Act
            var status = await provider.GetTransmissionStatusAsync(new GetTransmissionStatusArguments(handle));

            // Assert
            Assert.StartsWith("The session keys", status);
        }
        public async Task SendAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync();

            // Act
            using (var transaction = await provider.BeginTransactionAsync())
            {
                await provider.SendAsync(new SendArguments(handle));
                transaction.Rollback();
            }

            var received = await connection.QueryAsync("SELECT * FROM [TargetQueue] WITH (NOLOCK)");

            // Assert
            Assert.Empty(received);
        }
        public async Task GetTransmissionStatusAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync(encryption: true);

            // Act
            using (var transaction = await provider.BeginTransactionAsync())
            {
                await connection.ExecuteAsync("SEND ON CONVERSATION @handle;", new { handle }, transaction.UnderlyingTransaction);
                transaction.Rollback();
            }

            var status = await provider.GetTransmissionStatusAsync(new GetTransmissionStatusArguments(handle));

            // Assert
            Assert.Equal(string.Empty, status);
        }