Using the Windows Azure Service Bus REST API to Send to Topic from Salesforce.com

In the past, I’ve written and talked about integrating the Windows Azure Service Bus with non-Microsoft platforms like Salesforce.com. I enjoy showing how easy it is to use the Service Bus Relay to connect on-premises services with Salesforce.com. On multiple occasions, I’ve been asked how to do this with Service Bus brokered messaging options (i.e. Topics and Queues) as well. It can be a little tricky as it requires the use of the Windows Azure REST API and there aren’t a ton of public examples of how to do it! So in this blog post, I’ll show you how to send a message to a Service Bus Topic from Salesforce.com. Note that this sequence resembles how you’d do this on ANY platform that can’t use a Windows Azure SDK.

Creating the Topic and Subscription

First, I needed a Topic and Subscription to work with. Recall that Topics differ from Queues in that a Topic can have multiple subscribers. Each subscription (which may filter on message properties) has its own listener and gets their own copy of the message. In this fictitious scenario, I wanted users to submit IT support tickets from a page within the Salesforce.com site.

I could create a Topic in a few ways. First, there’s the Windows Azure portal. Below you can see that I have a Topic called “TicketTopic” and a Subscription called “AllTickets”.

2013.09.18topic01

If you’re a Visual Studio developer, you can also use the handy Windows Azure extensions to the Server Explorer window. Notice below that this tool ALSO shows me the filtering rules attached to each Subscription.

2013.09.18topic02

With a Topic and Subscription set up, I was ready to create a custom VisualForce page to publish to it.

Code to Get an ACS Token

Before I could send a message to a Topic, I needed to get an authentication token from the Windows Azure Access Control Service (ACS). This token goes into the request header and lets Windows Azure determine if I’m allowed to publish to a particular Topic.

In Salesforce.com, I built a custom VisualForce page with the markup necessary to submit a support ticket. The final page looks like this:

2013.09.18topic03

I also created a custom Controller that extended the native Accounts Controller and added an operation to respond to the “Submit Ticket” button event. The first bit of code is responsible for calling ACS and getting back a token that can be included in the subsequent request. Salesforce.com extensions are written in a language called Apex, but it should look familiar to any C# or Java developer.

       Http h= new Http();
       HttpRequest acReq = new HttpRequest();
       HttpRequest sbReq = new HttpRequest();

        // define endpoint and encode password
       String acUrl = 'https://seroter-sb.accesscontrol.windows.net/WRAPV0.9/';
       String encodedPW = EncodingUtil.urlEncode(sbUPassword, 'UTF-8');

       acReq.setEndpoint(acUrl);
       acReq.setMethod('POST');
       // choose the right credentials and scope
       acReq.setBody('wrap_name=demouser&wrap_password=' + encodedPW + '&wrap_scope=http://seroter.servicebus.windows.net/');
       acReq.setHeader('Content-Type','application/x-www-form-urlencoded');

       HttpResponse acRes = h.send(acReq);
       String acResult = acRes.getBody();

       // clean up result to get usable token
       String suffixRemoved = acResult.split('&')[0];
       String prefixRemoved = suffixRemoved.split('=')[1];
       String decodedToken = EncodingUtil.urlDecode(prefixRemoved, 'UTF-8');
       String finalToken = 'WRAP access_token=\"' + decodedToken + '\"';

This code block makes an HTTP request to the ACS endpoint and manipulates the response into the token format I needed.

Code to Send the Message to a Topic

Now comes the fun stuff. Here’s how you actually send a valid message to a Topic through the REST API. Below is the complete code snippet, and I’ll explain it further in a moment.

      //set endpoint using this scheme: https://<namespace>.servicebus.windows.net/<topic name>/messages
       String sbUrl = 'https://seroter.servicebus.windows.net/demotopic/messages';
       sbReq.setEndpoint(sbUrl);
       sbReq.setMethod('POST');
       // sending a string, and content type doesn't seem to matter here
       sbReq.setHeader('Content-Type', 'text/plain');
       // add the token to the header
       sbReq.setHeader('Authorization', finalToken);
       // set the Brokered Message properties
       sbReq.setHeader('BrokerProperties', '{ \"MessageId\": \"{'+ guid +'}\", \"Label\":\"supportticket\"}');
       // add a custom property that can be used for routing
       sbReq.setHeader('Account', myAcct.Name);
       // add the body; here doing it as a JSON payload
       sbReq.setBody('{ \"Account\": \"'+ myAcct.Name +'\", \"TicketType\": \"'+ TicketType +'\", \"TicketDate\": \"'+ SubmitDate +'\", \"Description\": \"'+ TicketText +'\" }');

       HttpResponse sbResult = h.send(sbReq);

So what’s happening here? First, I set the endpoint URL. In this case, I had to follow a particular structure that includes “/messages” at the end. Next, I added the ACS token to the HTTP Authorization header.

After that, I set the brokered messaging header. This fills up a JSON-formatted BrokerProperties structure that includes any values you needed by the message consumer. Notice here that I included a GUID for the message ID and provided a “label” value that I could access later. Next, I defined a custom header called “Account”. These custom headers get added to the Brokered Message’s “Properties” collection and are used in Subscription filters. In this case, a subscriber could choose to only receive Topic messages related to a particular account.

Finally, I set the body of the message. I could send any string value here, so I chose a lightweight JSON format that would be easy to convert to a typed object on the receiving end.

With all that, I was ready to go.

Receiving From Topic

To get a message into the Topic, I submitted a support ticket from the VisualForce page.

2013.09.18topic04

I immediately switched to the Windows Azure portal to see that a message was now queued up for the Subscription.

2013.09.18topic05

How can I retrieve this message? I could use the REST API again, but let’s show how we can mix and match techniques. In this case, I used the Windows Azure SDK for .NET to retrieve and delete a message from the Topic. I also referenced the excellent JSON.NET library to deserialize the JSON object to a .NET object. The tricky part was figuring out the right way to access the message body of the Brokered Message. I wasn’t able to simply pull it out a String value, so I went with a Stream instead. Here’s the complete code block:

           //pull Service Bus connection string from the config file
            string connectionString = ConfigurationManager.AppSettings["Microsoft.ServiceBus.ConnectionString"];

            //create a subscriptionclient for interacting with Topic
            SubscriptionClient client = SubscriptionClient.CreateFromConnectionString(connectionString, "tickettopic", "alltickets");

            //try and retrieve a message from the Subscription
            BrokeredMessage m = client.Receive();

            //if null, don't do anything interesting
            if (null == m)
            {
                Console.WriteLine("empty");
            }
            else
            {
                //retrieve and show the Label value of the BrokeredMessage
                string label = m.Label;
                Console.WriteLine("Label - " + label);

                //retrieve and show the custom property of the BrokeredMessage
                string acct = m.Properties["Account"].ToString();
                Console.WriteLine("Account - " + acct);

                Ticket t;

                //yank the BrokeredMessage body as a Stream
                using (Stream c = m.GetBody<Stream>())
                {
                    using (StreamReader sr = new StreamReader(c))
                    {
                        //get a string representation of the stream content
                        string s = sr.ReadToEnd();

                        //convert JSON to a typed object (Ticket)
                        t = JsonConvert.DeserializeObject<Ticket>(s);
                        m.Complete();
                    }
                }

                //show the ticket description
                Console.WriteLine("Ticket - " + t.Description);
            }

Pretty simple. Receive the message, extract interesting values (like the “Label” and custom properties), and convert the BrokeredMessage body to a typed object that I could work with. When I ran this bit of code, I saw the values we set in Salesforce.com.

2013.09.18topic06

Summary

The Windows Azure Service Bus brokered messaging services provide a great way to connect distributed systems. The store-and-forward capabilities are key when linking systems that span clouds or link the cloud to an on-premises system. While Microsoft provides a whole host of platform-specific SDKs for interacting with the Service Bus, there are platforms that have to use the REST API instead. Hopefully this post gave you some insight into how to use this API to successfully publish to Service Bus Topics from virtually ANY software platform.

Author: Richard Seroter

Richard Seroter is Director of Developer Relations and Outbound Product Management at Google Cloud. He’s also an instructor at Pluralsight, a frequent public speaker, the author of multiple books on software design and development, and a former InfoQ.com editor plus former 12-time Microsoft MVP for cloud. As Director of Developer Relations and Outbound Product Management, Richard leads an organization of Google Cloud developer advocates, engineers, platform builders, and outbound product managers that help customers find success in their cloud journey. Richard maintains a regularly updated blog on topics of architecture and solution design and can be found on Twitter as @rseroter.

14 thoughts

  1. Good stuff, thanks. But I keep getting a 401 – Invalid authorization token signature – when I send a message. The SWT token looks fine as far as I can tell, so I think it’s a problem with the way I’ve set up ACS. Any tips on that?

    1. Hey Mike. Are you using the password or the key to authenticate? I sometimes get a messed up ACS account where I’m passing in the wrong credentials! Look at the ACS portal and try both values.

  2. Is there also a way of doing this the other way round? So my Azure app adds a message to a Topic and a third-party customer who subscribes to that Topic using an HTTP endpoint (using a non-.NET system) receives this message?

      1. Hi Richard
        Thanks for your article. It was really helpful. I’m using the REST API to receive a message according to the above document in MSDN. However I’m getting “The specified HTTP verb (POST) is not valid”, HTTP 400 error when try to retrieve the message. Any idea why? I’m using SAS for authentication. The send message works fine.
        Cheers
        Manoj

        1. Did you ever figure this out getting “The specified HTTP verb (POST) is not valid.” I’m getting the same error trying to call /$deadletterqueue

  3. You are using Azure service bus in the cloud. If I were to use on premise Service Bus for windows server and I have the port 9355 open and ssl enabled, how can I send a message to the queue from salesforce and also pick up from the queue? Do I use Shared Access Signature Authentication? Is that similar to adding ACS token to the HTTP Authorization header?

      1. That’s the plan. We are planning to test it out. I was wondering if you had any suggestions.

        1. Nothing comes to mind. If the ports are open, I don’t see any obvious reason it wouldn’t work. That said, you’ll want to be careful about security and opening up a service like that to public internet traffic.

  4. Do you know what should I configure security related in salesforce in addition to workflow rule and outbound message to send the xml message to an azure topic or queue?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.