D365: Post custom message to Azure Service Bus Queue C#

In this post, we’ll see how we can post custom message to Azure Service Bus Queue.

Let’s go to Azure portal and Create a Service Bus Namespace.

Search for Service Bus

Click Create

Give a Name and Click on Create

After creating Service Bus Namespace, Browse through it and go to Shared Access Policies. Click Add to create a new policy.
Give a Policy Name, Select Send and Listen and click Create.

Click on Policy Name created and copy the Primary Connection String. We’ll use this to post message to the queue inside this Service Bus Namespace.

Inside Service Bus Namespace, Click on Queues –> +Queue to create a new Queue.

Give a Name to the Queue and click Create.

Browse through the Queue created to see that there no messages.

Now, we’ll use C# to post custom message(with required information only to process) to the queue.

public static void PostMessageToServiceBusQueue(dxc_rate rate)
{
 TimeSpan ts = new TimeSpan(0, 0, 90);
var ServiceBusNamespaceURL = "sb://demoazure.servicebus.windows.net";
var ServiceBusQueueURL = "https://demoazure.servicebus.windows.net/demoqueue/messages";
var SASKeyName = "IntegrationKey";
var SASKeyValue = "qkWTne2zdLQvJv6qp2+G1eqNau7XGfZZlZAEQTV9Y+A=";
                string sasToken = Common.GetSASToken(ServiceBusNamespaceURL, SASKeyName, SASKeyValue, ts);

                RateObject rateObject = new RateObject
                {
                    RateID = rate.dxc_rateId.ToString(),
                    EndDate = rate.dxc_EndDate == null ? string.Empty : rate.dxc_EndDate.ToString(),
                    StartDate = rate.dxc_StartDate == null ? string.Empty : rate.dxc_StartDate.ToString(),
                    RateAmount = rate.dxc_Rate == null ? string.Empty : rate.dxc_Rate.Value.ToString(),
                    RatePercentage = rate.dxc_RatePercentage == null ? string.Empty : rate.dxc_RatePercentage.ToString(),
                    RateModel = rate.dxc_ratemodel == null ? string.Empty : rate.dxc_ratemodel.Value.ToString(),
                    RevenueCodeID = rate.dxc_RevenueCodeId == null ? string.Empty : rate.dxc_RevenueCodeId.Id.ToString()
                };
                var json = Common.SerializeToJsonString(rateObject);
                HttpClient client = new HttpClient();
                client.DefaultRequestHeaders.Add("Authorization", sasToken);
                var Content = new StringContent(json, Encoding.UTF8, "application/json");
                var response = client.PostAsync(ServiceBusQueueURL, Content);
                response.Wait();
}

Below is the code to get SAS token.

 public static string GetSASToken(string resourceUri, string keyName, string key, TimeSpan ttl)
        {
            var expiry = GetExpiry(ttl);
            //string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
            //NOTE: UrlEncode is not supported in CRM, use System.Uri.EscapeDataString instead
            string stringToSign = Uri.EscapeDataString(resourceUri).ToLowerInvariant() + "\n"
                 + expiry;
            HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));

            var signature =
            Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
            var sasToken = String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}", Uri.EscapeDataString(resourceUri).ToLowerInvariant(),
       Uri.EscapeDataString(signature), expiry, keyName);
            return sasToken;
        }

  public static string GetExpiry(TimeSpan ttl)
        {
            var expirySinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1) + ttl;
            return Convert.ToString((int)expirySinceEpoch.TotalSeconds);
        }

Below is the code to serialize C# object.

  public static string SerializeToJsonString(object objectToSerialize)
        {
            // Create a stream to serialize the object to.
            using (var ms = new MemoryStream())
            {
                // Serializer the User object to the stream.
                var ser = new System.Runtime.Serialization.Json.DataContractJsonSerializer(objectToSerialize.GetType());
                ser.WriteObject(ms, objectToSerialize);
                byte[] json = ms.ToArray();
                ms.Close();
                return Encoding.UTF8.GetString(json, 0, json.Length);
            }
        }

Below is the RateObject class decorated with DataContract attribute and it’s properties decorated with DataMember attribute.

 [DataContract]
    public class RateObject
    {
        [DataMember]
        public string RateID { get; set; }

        [DataMember]
        public string RateAmount { get; set; }

        [DataMember]
        public string RatePercentage { get; set; }

        [DataMember]
        public string RateModel { get; set; }

        [DataMember]
        public string RevenueCodeID { get; set; }

        [DataMember]
        public string StartDate { get; set; }

        [DataMember]
        public string EndDate { get; set; }

    }

The above code can be used in plugin/custom workflow to post message to a queue.

We executed the above code on Post Update of Rate(entity) record and we can see that the message has been received in queue.

We can use Service Bus Explorer to see the message details:

And in Azure Portal, we can also see that the message has been received.

Hope it helps !!

11 thoughts on “D365: Post custom message to Azure Service Bus Queue C#

      1. Thank you. Also, another question, does this code work for Azure Service Bus Topics as well? If yes, the url would the same as the one for queue but with the topic name after / ?

        Like

  1. I tested it for topic and it is working very well. But I changed the code a little bit: I did not used the ServiceBusNamespaceURL at all, all I needed was queue/topic URL of format: https://.servicebus.windows.net//messages, sharedKey, sharedKeyName, timetolive in order to generate the Authentication Token. Also I sent the request to queue/topic URL. I don’t know if it was working in the past with the request being sent to the ServiceBusNamespaceUrl but now I got status 401. Thank you again Ajit for your work, it guided me to the right way.

    Like

Leave a comment

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