18

I have created a very simple console application that connects to Azure ServiceBus and sends one message. I tried the latest library from Microsoft (Microsoft.Azure.ServiceBus) but no matter what I do I just get this error:

No connection could be made because the target machine actively refused it ErrorCode: ConnectionRefused

I have tried exactly the same connection string in Service Bus Explorer and it does work just fine. Moreover I connected without problems using the older library from Microsoft (WindowsAzure.ServiceBus).

var sender = new MessageSender("endpoint", "topicName");
sender.SendAsync(new Message(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject("test"))));

I tried with .NET Framework 4.6.2 and Core, same exception. I suspect there may be some differences in the default protocol that these libraries use, but I could not figure out that for sure.

P.S. Have tried the example from Microsoft docs but result is still the same exception

Ilya Chernomordik
  • 27,817
  • 27
  • 121
  • 207

3 Answers3

24

The old client supported ConnectivityMode using TCP, HTTP, HTTPS, and AutoDetect. ServiceBus Explorer is using AutoDetect, trying TCP first and then failing over to HTTPS, regardless of the TransportMode you were using (SBMP or AMQP).

With the new client this has changed. TransportMode now combines both options and offers Amqp (AMQP over TCP) or AmqpWebSockets (AMQP over WebSockets). There's no AutoDetect mode. You will have to create your clients and specify TransportType as AmqpWebSockets to bypass blocked TCP port 5671 and instead use port 443.

Sean Feldman
  • 23,443
  • 7
  • 55
  • 80
  • Thanks a lot for the answer, I will try to do that, though I did not manage to find exactly where do I need to set the TransportType in the new library. I have not found a good documentation on these details, but'll try to search some more with your tips! – Ilya Chernomordik Jun 09 '18 at 13:53
  • `MessageSender` constructor overload taking FQDN of your endpoint and `TokenProvider` is the one you need. Make sure you use the latest, 3.0.2 as of today. – Sean Feldman Jun 09 '18 at 13:58
  • Thanks! I managed to connect, though it was not right away obvious and lacking a bit in documentation on how to get TokenProvider. – Ilya Chernomordik Jun 11 '18 at 10:24
  • Yeah, I agree with you about clarity of that API. There really should be an overload taking a string and a transport type to save developers this unnecessary boiler-plating. – Sean Feldman Jun 11 '18 at 14:49
  • 3
    I have actually just found an easier way, we can extend connection string with the protocol: `TransportType=AmqpWebSockets;...` – Ilya Chernomordik Jun 11 '18 at 14:55
  • Have posted all the different varians I have found as an additional answer – Ilya Chernomordik Jun 11 '18 at 15:08
  • 1
    "It is actually possible to use ConnectionString directly but then it has to be augmented to use the right protocol." what I meant is to use a connection string and a separate optional argument for `TransportType`. Either way, documentation could use some help :) – Sean Feldman Jun 11 '18 at 18:08
  • @SeanFeldman - We have a very diverse set of customers with different network environments - some will allow https thought, some will allow the native TCP through etc.. With the old library, this fell through each transport down to the best possible supported one, but with this new library we are being asked to either tell clients how to open their network or provide a different configuration for each? This is not ideal. Why can we not get a similar extension that at least accepts AutoDetect as a transport and falls back accordingly? – pseabury May 28 '21 at 01:45
  • 1
    @pseabury great question but you're asking the wrong person This is more suited for Azure SDK team at https://github.com/Azure/azure-sdk-for-net/ – Sean Feldman May 28 '21 at 02:37
17

It seems that the documentation is lacking a lot on how to connect using HTTPS (Amqp over WebSockets) but after some help from Sean Feldman in the accepted answer I managed to connect. Here is the code that I used if someone is interested:

var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(
    "RootManageSharedAccessKey", // SharedAccessKeyName
    "SomeToken");

var sender = new MessageSender(
    "sb://mydomain.servicebus.windows.net/",
    "topicName",
    tokenProvider,
    TransportType.AmqpWebSockets);

Or a variant that let's you have the whole connection string in one piece

var builder = new ServiceBusConnectionStringBuilder("YouConnectionString");

var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(
    builder.SasKeyName,
    builder.SasKey);

var sender = new MessageSender(
    builder.Endpoint,
    "TopicName",
    tokenProvider,
    TransportType.AmqpWebSockets);

It is actually possible to use ConnectionString directly but then it has to be augmented to use the right protocol.

var sender = new MessageSender("TransportType=AmqpWebSockets;Endpoint=...", "TopicName")

Or the version that allows to embed EntityPath into the ConnectionString

var connectionBuilder = new ServiceBusConnectionStringBuilder("EntityPath=MyTopic;TransportType=AmqpWebSockets;Endpoint=...")
var sender = new MessageSender(connectionBuilder);
Ilya Chernomordik
  • 27,817
  • 27
  • 121
  • 207
  • 1
    I was getting connection timeout error from behind a restrictive corporate firewall, adding the TransportType=AmqpWebSockets; to my connection string fixed it. – ilikeprogramming Jan 08 '19 at 15:29
  • I had the "TransportType=xxxxxx" in my connection string, still did not work, I had to set transport-type specifically with the ServiceBusClientOptions when creating the service-bus-client. .Net Core 3.1. Accessing Azure Service Bus namespace from a very locked down machine. I also set proxy via HttpClient.DefaultProxy. – joanygaard Aug 25 '21 at 20:52
  • I also noticed that the service-bus-management-client (used to get queue message counts etc) seemed to work fine with same connection string. – joanygaard Aug 25 '21 at 20:58
2

I was having the same issue but this worked for me

var clientOptions = new ServiceBusClientOptions();
clientOptions.TransportType = ServiceBusTransportType.AmqpWebSockets;
client = new ServiceBusClient(connectionString, clientOptions);
sender = client.CreateSender(topicName);
// create a batch 
using ServiceBusMessageBatch messageBatch = await sender.CreateMessageBatchAsync();
Ali
  • 1,015
  • 14
  • 40