Friday, September 14, 2012

BizTalk 2010 R2 CTP: Azure Service Bus Integration–Part 1

Back in June 2012, I had the opportunity to attend TechEd North America.  At this event the BizTalk team gave us a glimpse into the next version of BizTalk and went over the Product Road map.  You can read more about this Roadmap session here.

One of the areas that Microsoft wanted to address was better/seamless integration with Azure and more specifically with Service Bus Queues and Topics.  The BizTalk team released a feature pack back in October 2010 that better enabled BizTalk to leverage the Service Bus Relay capabilities.  This feature pack does work well but did not allow for connectivity to Service Bus Queues and Topics since they weren’t even available back then.

In the fall of 2011, the talented Paolo Salvatori wrote a very detailed article on how you can integrate BizTalk 2010 with Service Bus Queues and Topics.  While Paolo’s solution does work it does require some additional effort and some people may be a little overwhelmed by the solution.  But I do give credit to Microsoft and Paolo for coming up with a solution considering BizTalk 2010 was released much before Service Bus Queues and Topics were commercially available.  Their solution just validates why BizTalk leveraging WCF is a good idea.  When investments are made to WCF, BizTalk usually benefits. All in all, it was a good stop-gap for anyone desperate to integration BizTalk 2010 with Azure.

Fast forward to July 2012 when Microsoft released this BizTalk 2010 R2 CTP.  Microsoft has delivered on making integration with Service Bus Queues and Topics very simple.  The BizTalk team recently released a blog post which provides an overview of some of these new features.  I thought it would be beneficial to provide a walk through for anyone interested in more details than what Microsoft included in that post.

Scenario

The scenario that we are about to explore includes a client application that will publish a typed Brokered message from a Console application to a Service Bus Queue.  BizTalk will then use the new SB-Messaging adapter to retrieve the message and simply write it to the file system.  As an experienced BizTalk guy, I like strongly typed messages and I am not afraid to admit it.  So as part of this solution I am going to include a strongly typed BizTalk schema that I am going to deploy.  For this walkthrough I am not going to transform this message but for anyone familiar with BizTalk they will be able to take this solution adapt it for their needs.

Client Application

  • Launch Visual Studio 2012 and create a C# Console application.  I called my application BrokeredMessageToBizTalk

image

  • Next I will use the Nuget Package manager and installing the Windows Azure Service Bus package.  You can access Nuget by clicking the following within Visual Studio: Tools - Library Package Manager - Manage Nuget Packages for Solution.

image

  • Since I want deal with typed messages I am going to create a class called PowerOut.  Since I work in the Power Industry I will over-simplify a use case that involves a customer whose power is out.  They will send a message from a client application (it could be a web page, mobile phone app etc) to a Service Bus Queue.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BrokeredMessageToBizTalk
{
    public class PowerOut
    {
        public string CustomerName;
        public string PhoneNumber;
        public string Address;
       
    }
}

  • Within our Program.cs file we want to include the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ServiceBus;
using Microsoft.ServiceBus.Messaging;
using System.Runtime.Serialization;
using System.IO;

namespace BrokeredMessageToBizTalk
{
    class Sender
    {
   
        const string QueueName = "PowerOutageQueue";
        static string ServiceNamespace = "YOUR_NAMESPACE";
        static string IssuerName ="owner";
        static string IssuerKey = "YOUR_KEY”;

        static void Main(string[] args)
        {
            //*****************************************************************************************************
            //                                   Get Credentials
            //*****************************************************************************************************          
            TokenProvider credentials = TokenProvider.CreateSharedSecretTokenProvider(Sender.IssuerName, Sender.IssuerKey);
            Uri serviceUri = ServiceBusEnvironment.CreateServiceUri("sb", Sender.ServiceNamespace, string.Empty);

            MessagingFactory factory = null;

            try
            {
                //***************************************************************************************************
                //                                   Management Operations
                //***************************************************************************************************       
                NamespaceManager namespaceClient = new NamespaceManager(serviceUri, credentials);
                if (namespaceClient == null)
                {
                    Console.WriteLine("\nUnexpected Error: NamespaceManager is NULL");
                    return;
                }

                Console.WriteLine("\nCreating Queue '{0}'...", Sender.QueueName);

                // Delete if exists
                if (namespaceClient.QueueExists(Sender.QueueName))
                {
                    namespaceClient.DeleteQueue(Sender.QueueName);
                }

                namespaceClient.CreateQueue(Sender.QueueName);

                //***************************************************************************************************
                //                                   Runtime Operations
                //***************************************************************************************************
                factory = MessagingFactory.Create(serviceUri, credentials);

                QueueClient myQueueClient = factory.CreateQueueClient(Sender.QueueName);

                //***************************************************************************************************
                //                                   Sending messages to a Queue
                //***************************************************************************************************
               

                Console.WriteLine("\nSending messages to Queue...");

                //Create new instance of PowerOut object
                PowerOut po = new PowerOut();
                po.CustomerName = "Stephen Harper";
                po.PhoneNumber = "613-123-4567";
                po.Address = "24 Sussex Drive";

                BrokeredMessage message = new BrokeredMessage(po, new DataContractSerializer(typeof(PowerOut)));
              
                myQueueClient.Send(message);
             

                //Uncomment this code if you want to write a sample file to disk

                //using (FileStream writer = new FileStream("c:/temp/file.xml",FileMode.Create, FileAccess.Write))
                //{
                //    DataContractSerializer ser = new DataContractSerializer(typeof(PowerOut));
                //    ser.WriteObject(writer, po);
                //}

                Console.WriteLine("\nAfter running the entire sample, press ENTER to exit.");
                Console.ReadLine();
            }
            catch (Exception e)
            {
                Console.WriteLine("Unexpected exception {0}", e.ToString());
                throw;
            }
            finally
            {
                // Closing factory close all entities created from the factory.
                if(factory != null)
                    factory.Close();
            }
           
        }

    }
}

Of the code above I want to highlight a couple different lines:

  • The first one deals with the DataContractSerializer as seen below.        

BrokeredMessage message = new BrokeredMessage(po, new DataContractSerializer(typeof(PowerOut)));

If you do not use a DataContractSerializer you can expect undesirable results when BizTalk retrieves the message from the queue.  As mentioned in the recent BizTalk team blog post: “Brokered Message .NET API uses Binary encoding. To avoid this issue, you will need to use Text by explicitly provide your own serializer, instead of the default serializer.”

  • The next deals with the few lines that have been commented out.  Since I want to use typed messages within BizTalk, I can generate a sample XML message using the code below.  This will allow me to generate a BizTalk schema using tools provided within Visual Studio.

    //using (FileStream writer = new FileStream("c:/temp/file.xml",FileMode.Create, FileAccess.Write))
                //{
                //    DataContractSerializer ser = new DataContractSerializer(typeof(PowerOut));
                //    ser.WriteObject(writer, po);
                //}

*As a side note – wouldn’t it be nice if BizTalk supported native .Net Classes (from a messaging perspective) - hint, hint *

BizTalk Application

We can now create a BizTalk application.  Since we are using the new BizTalk 2010 R2 CTP we can also use the latest version of Visual Studio 2012.  As I mentioned earlier I want to process typed messages so our BizTalk solution will be very simple.  It will only include a Schema.  We will deploy this message to BizTalk so that when an instance of this message is published to the MessageBox that we will have a known schema deployed that will match this message type.

  • We can now create a new BizTalk application. I have called mine PowerOutage and I have also added a Strong Name Key called PowerOutage.snk.

image

  • Next I want to create a new Schema based upon the sample file that we previously generated.  I can create this new schema by right mouse clicking on BizTalk project (PowerOutage) - Add - Add Generated Items.
  • When prompted, click on the Generate Schemas label and then click the Add button.

image

  • Select Well-Formed XML from the Document type dropdown and then we need to provide the name of our sample file.  Click OK to proceed.

image

  • We will now have a schema added to our solution that represents our PowerOutage class.

image

  • Deploy our BizTalk Application
  • When we launch the BizTalk Admin Console we will discover our PowerOutage application.
  • We now need to create a Receive Port and corresponding Receive Location.  In this situation we are going to use the SB-Messaging Adapter.

image

  • When we click the Configure button we will have a few more properties to fill out including our URL.  Our URL is going to include our Namespace (highlighted in Green) and our QueueName (highlighted in Orange)

image

  • Next we need to click on the Authentication tab.  Within this tab we will provide our Namespace as it relates to the Access Control Servers (ACS), an our Issuer Name and Key.

image

  • The Properties tab is not used in this example.  I will further examine it in a later post.
  • With our Receive Port and Receive Location created we can no move on to our Send Port.  For this example we are simply going to create a File Drop where we can write out the file that we have received from the Service Bus Queue.

image

  • Since we do not have any Orchestrations we do need to wire up a subscription for our inbound message.  In order to do this we will simply create a “Send Port Subscription” by setting filter.

image

  • We can now Start our BizTalk application and bounce our Host Instance(if applicable)

Testing our scenario

  • Next, launch our Console Application and we will discover that our message has been sent to our Queue.

image

  • If we check the File Drop that was specified in our Send Port we should see a newly created file.  When we open this file we should recognize the content that we populated in our Console application.  Since we now have typed data within BizTalk it will be easy to transform it into other message types so that we can exchange data with other systems such as Line of Business (LOB) systems.

image

Conclusion

Now that wasn’t so bad was it?  For experienced BizTalk people this process should be a breeze.  The only area that initially hung me up was the DataContractSerialzer that is specified in our console application.  The other good news is that we are just scratching the surface in this blog post.  Look for more posts related to BizTalk and Service Bus integration using the new BizTalk 2010 R2 CTP.

4 comments:

Mark Brimble said...

Well done. I had been trying to work out this same scenario for myself and your article has got me through all the roadblocks. Thanks for posting.

Kent Weare said...

Thanks Mark - glad you found it beneficial

Deepak said...

I followed your article but I am getting the following error while receiving the message in Biztalk

The adapter "WCF-Custom" raised an error message. Details "System.Xml.XmlException: The input source is not correctly formatted.

I am using WCF Custom adapter to receive the message.

Kent Weare said...

Deepak,

There are two things that I can think of

1. Make sure you are using new SB-Messaging adapter

2. Make sure your serialization of your incoming message is text based. There is a section on this blog post about serialization.