Skip to main content

How to integrate BizTalk Server 2010 / 2013 with Service Bus for Windows Server

This solution shows how to integrate a BizTalk Server 2010/2013 application with Service Bus for Windows Server using the WCF-Custom adapter to exchange messages with external systems in a reliable, flexible, and scalable manner.

C# (5.3 MB)
 
 
 
 
 
4.7 Star
(6)
1,708 times
Add to favorites
6/20/2014
E-mail Twitter del.icio.us Digg Facebook

Solution explorer

C#
#region Copyright
//=======================================================================================
//Microsoft Windows Server AppFabric Customer Advisory Team (CAT)  
//
// This sample is supplemental to the technical guidance published on the community
// blog at http://blogs.msdn.com/paolos. 
// 
// Author: Paolo Salvatori
//=======================================================================================
// Copyright © 2011 Microsoft Corporation. All rights reserved.
// 
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF 
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. YOU BEAR THE RISK OF USING IT.
//=======================================================================================
#endregion

#region Using Directives
using System;
using System.IO;
using System.Diagnostics;
using System.Globalization;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
using Microsoft.ServiceBus.Messaging;
using Microsoft.WindowsAzure.CAT.Samples.ServiceBusForWindowsServer.Service;
using Microsoft.WindowsAzure.CAT.Samples.ServiceBusForWindowsServer.DataContracts;
using Microsoft.WindowsAzure.CAT.Samples.ServiceBusForWindowsServer.MessageContracts;
using Microsoft.WindowsAzure.CAT.Samples.ServiceBusForWindowsServer.ServiceContracts;
#endregion

namespace Microsoft.WindowsAzure.CAT.Samples.ServiceBusForWindowsServer.Client
{
    public partial class MainForm : Form
    {
        #region Private Constants
        //***************************
        // Formats
        //***************************
        private const string DateFormat = "<{0,2:00}:{1,2:00}:{2,2:00}> {3}";
        private const string ExceptionFormat = "Exception: {0}";
        private const string InnerExceptionFormat = "InnerException: {0}";
        private const string LogFileNameFormat = "ServiceBusExplorer {0}.txt";

        //***************************
        // Constants
        //***************************
        private const string SaveAsTitle = "Save Log As";
        private const string SaveAsExtension = "txt";
        private const string SaveAsFilter = "Text Documents|*.txt";
        private const string PropertyOperand1 = "Operand1";
        private const string PropertyOperator = "Operator";
        private const string PropertyOperand2 = "Operand2";
        private const string PropertyKey = "Key";
        private const string PropertyType = "Type";
        private const string PropertyValue = "Value";
        private const string DefaultLabel = "WindowsAzureCAT";
        private const string StringType = "String";

        //***************************
        // Messages
        //***************************
        private const string PropertyValueCannotBeNull = "The value of the {0} property cannot be null.";
        private const string PropertyConversionError = "{0} property conversion error: {1}";
        private const string WarningHeader = "The following validations failed:";
        private const string WarningFormat = "\n\r - {0}";
        private const string SentMessagePropertiesHeader = "Properties:";
        private const string MessagePropertyFormat = " - Key=[{0}] Value=[{1}]";
        private const string MessageSuccessfullySent = "Request Message Sent:\n - EndpointUrl:[{0}]\n - MessageId=[{1}]\n - SessionId=[{2}]\n - Label=[{3}]\n - Elapsed Time (ms)=[{4}]";
        private const string RequestFormat = " - Operation[{0}]: [{1} {2} {3}]";
        private const string OperationListCannotBeNull = "The operation list cannot be null.";
        private const string ServiceHostSuccessfullyOpened = "The response handler service was successfully opened.";
        private const string ServiceHostListeningOnQueue = "The service is listening on the {0} queue.";
        private const string ServiceHostListeningOnSubscription = "The service is listening on the {0} subscription.";
        private const string PayloadFormat = "Payload:";
        private const string EndpointConfigurationNameCannotBeNull = "The endpoint configuration name cannot be null.";
        #endregion

        #region Private Instance Fields
        private readonly OperationList operationList = new OperationList();
        private BindingSource operationsBindingSource;
        private BindingSource propertiesBindingSource;
        private string responseQueueUri;
        private string responseTopicUri;
        private readonly Dictionary<string, ChannelFactory<ICalculatorRequest>> channelFactoryDictionary = new Dictionary<string, ChannelFactory<ICalculatorRequest>>();
        private readonly Dictionary<string, ICalculatorRequest> channelDictionary = new Dictionary<string, ICalculatorRequest>();
        private readonly string sessionId = Guid.NewGuid().ToString();
        #endregion

        #region Private Static Fields
        private static MainForm mainForm;
        private static readonly List<string> types = new List<string> { "Boolean", "Byte", "Int16", "Int32", "Int64", "Single", "Double", "Decimal", "Guid", "DateTime", "String" };
        private static readonly List<string> operations = new List<string> { "+", "-", "*", "/"};
        #endregion

        #region Public Constructor
        /// <summary>
        /// Initializes a new instance of the MainForm class.
        /// </summary>
        public MainForm()
        {
            InitializeComponent();
            InitializeControls();
            StartServiceHost();
        }
        #endregion

        #region Public Methods
        public void WriteToLog(string message)
        {
            if (InvokeRequired)
            {
                Invoke(new Action<string>(InternalWriteToLog), new object[] { message });
            }
            else
            {
                InternalWriteToLog(message);
            }
        }

        public void HandleException(Exception ex)
        {
            if (ex != null && !string.IsNullOrEmpty(ex.Message))
            {
                WriteToLog(string.Format(CultureInfo.CurrentCulture, ExceptionFormat, ex.Message));
                if (ex.InnerException != null && !string.IsNullOrEmpty(ex.InnerException.Message))
                {
                    WriteToLog(string.Format(CultureInfo.CurrentCulture, InnerExceptionFormat, ex.InnerException.Message));
                }
            }
        }
        #endregion

        #region Public Static Properties
        public static void StaticWriteToLog(string message)
        {
            mainForm.WriteToLog(message);
        }

        public static void StaticHandleException(Exception ex)
        {
            mainForm.HandleException(ex);
        }
        #endregion

        #region Private Methods
        private void InitializeControls()
        {
            try
            {
                // Initialize private fields
                mainForm = this;
                operationsBindingSource = new BindingSource();
                propertiesBindingSource = new BindingSource();

                // Initialize the Properties DataGridView.
                operationsDataGridView.AutoGenerateColumns = false;
                operationsDataGridView.AutoSize = true;
                operationsDataGridView.DataSource = operationsBindingSource;
                operationsDataGridView.ForeColor = SystemColors.WindowText;

                // Create the Name column
                var textBoxColumn = new DataGridViewTextBoxColumn
                                        {
                                            DataPropertyName = PropertyOperand1, 
                                            Name = PropertyOperand1, 
                                            Width = 68
                                        };
                operationsDataGridView.Columns.Add(textBoxColumn);

                // Create the Type column
                var comboBoxColumn = new DataGridViewComboBoxColumn
                                         {
                                             DataSource = operations,
                                             DataPropertyName = PropertyOperator,
                                             Name = PropertyOperator,
                                             Width = 60
                                         };
                operationsDataGridView.Columns.Add(comboBoxColumn);

                // Create the Value column
                textBoxColumn = new DataGridViewTextBoxColumn
                                    {
                                        DataPropertyName = PropertyOperand2, 
                                        Name = PropertyOperand2, 
                                        Width = 68
                                    };
                operationsDataGridView.Columns.Add(textBoxColumn);

                // Create operation items
                operationsDataGridView.Rows.Clear();
                var operation = new Operation("+", 84, 61);
                operationList.Add(operation);
                operation = new Operation("-", 68, 43);
                operationList.Add(operation);
                operation = new Operation("*", 15, 8);
                operationList.Add(operation);
                operation = new Operation("/", 96, 16);
                operationList.Add(operation);
                operationsBindingSource.DataSource = operationList;
                operationsBindingSource.ResetBindings(false);

                // Initialize the Properties of the BrokeredMessage that will be sent to BizTalk
                propertiesBindingSource.Add(new PropertyInfo("Method", "String", "Static"));
                propertiesBindingSource.Add(new PropertyInfo("Country", "String", "Italy"));
                propertiesBindingSource.Add(new PropertyInfo("City", "String", "Milan"));
                propertiesBindingSource.Add(new PropertyInfo("MachineName", "String", Environment.MachineName));
                propertiesBindingSource.Add(new PropertyInfo("UserName", "String", Environment.UserName));
                
                // Initialize the Properties DataGridView.
                propertiesDataGridView.AutoGenerateColumns = false;
                propertiesDataGridView.AutoSize = true;
                propertiesDataGridView.DataSource = propertiesBindingSource;
                propertiesDataGridView.ForeColor = SystemColors.WindowText;

                // Create the Name column
                textBoxColumn = new DataGridViewTextBoxColumn
                                    {
                                        DataPropertyName = PropertyKey, 
                                        Name = PropertyKey, 
                                        Width = 100
                                    };
                propertiesDataGridView.Columns.Add(textBoxColumn);

                // Create the Type column
                comboBoxColumn = new DataGridViewComboBoxColumn
                                     {
                                         DataSource = types,
                                         DataPropertyName = PropertyType,
                                         Name = PropertyType,
                                         Width = 60
                                     };
                propertiesDataGridView.Columns.Add(comboBoxColumn);

                // Create the Value column
                textBoxColumn = new DataGridViewTextBoxColumn
                                    {
                                        DataPropertyName = PropertyValue, 
                                        Name = PropertyValue, 
                                        Width = 100
                                    };
                propertiesDataGridView.Columns.Add(textBoxColumn);

                // Initialize the Label textbox
                txtLabel.Text = DefaultLabel;

                propertiesDataGridView.EnableHeadersVisualStyles = false;

                // Set the selection background color for all the cells.
                propertiesDataGridView.DefaultCellStyle.SelectionBackColor = Color.FromArgb(153, 180, 209);
                propertiesDataGridView.DefaultCellStyle.SelectionForeColor = Color.White;

                // Set RowHeadersDefaultCellStyle.SelectionBackColor so that its default 
                // value won't override DataGridView.DefaultCellStyle.SelectionBackColor.
                propertiesDataGridView.RowHeadersDefaultCellStyle.SelectionBackColor = Color.FromArgb(153, 180, 209);

                // Set the background color for all rows and for alternating rows.  
                // The value for alternating rows overrides the value for all rows. 
                propertiesDataGridView.RowsDefaultCellStyle.BackColor = Color.FromArgb(238, 242, 245);
                propertiesDataGridView.RowsDefaultCellStyle.ForeColor = SystemColors.ControlText;
                propertiesDataGridView.AlternatingRowsDefaultCellStyle.BackColor = Color.White;
                propertiesDataGridView.AlternatingRowsDefaultCellStyle.ForeColor = SystemColors.ControlText;

                // Set the row and column header styles.
                propertiesDataGridView.RowHeadersDefaultCellStyle.BackColor = Color.FromArgb(215, 228, 242);
                propertiesDataGridView.RowHeadersDefaultCellStyle.ForeColor = SystemColors.ControlText;
                propertiesDataGridView.ColumnHeadersDefaultCellStyle.BackColor = Color.FromArgb(215, 228, 242);
                propertiesDataGridView.ColumnHeadersDefaultCellStyle.ForeColor = SystemColors.ControlText;

                operationsDataGridView.EnableHeadersVisualStyles = false;

                // Set the selection background color for all the cells.
                operationsDataGridView.DefaultCellStyle.SelectionBackColor = Color.FromArgb(153, 180, 209);
                operationsDataGridView.DefaultCellStyle.SelectionForeColor = Color.White;

                // Set RowHeadersDefaultCellStyle.SelectionBackColor so that its default 
                // value won't override DataGridView.DefaultCellStyle.SelectionBackColor.
                operationsDataGridView.RowHeadersDefaultCellStyle.SelectionBackColor = Color.FromArgb(153, 180, 209);

                // Set the background color for all rows and for alternating rows.  
                // The value for alternating rows overrides the value for all rows. 
                operationsDataGridView.RowsDefaultCellStyle.BackColor = Color.FromArgb(238, 242, 245);
                operationsDataGridView.RowsDefaultCellStyle.ForeColor = SystemColors.ControlText;
                operationsDataGridView.AlternatingRowsDefaultCellStyle.BackColor = Color.White;
                operationsDataGridView.AlternatingRowsDefaultCellStyle.ForeColor = SystemColors.ControlText;

                // Set the row and column header styles.
                operationsDataGridView.RowHeadersDefaultCellStyle.BackColor = Color.FromArgb(215, 228, 242);
                operationsDataGridView.RowHeadersDefaultCellStyle.ForeColor = SystemColors.ControlText;
                operationsDataGridView.ColumnHeadersDefaultCellStyle.BackColor = Color.FromArgb(215, 228, 242);
                operationsDataGridView.ColumnHeadersDefaultCellStyle.ForeColor = SystemColors.ControlText;
            }
            catch (Exception ex)
            {
                mainForm.HandleException(ex);
            }
        }

        private void StartServiceHost()
        {
            try
            {
                // Creating the service host object as defined in config
                var serviceHost = new ServiceHost(typeof(ResponseHandlerService));
                
                // Add ErrorServiceBehavior for handling errors encounter by servicehost during execution.
                serviceHost.Description.Behaviors.Add(new ErrorServiceBehavior());


                foreach (var serviceEndpoint in serviceHost.Description.Endpoints)
                {
                    if (serviceEndpoint.Name == "responseQueueServiceEndpoint")
                    {
                        responseQueueUri = serviceEndpoint.Address.Uri.AbsoluteUri;
                        WriteToLog(string.Format(ServiceHostListeningOnQueue,
                                             serviceEndpoint.Address.Uri.AbsoluteUri));
                    }
                    if (serviceEndpoint.Name == "responseSubscriptionServiceEndpoint")
                    {
                        responseTopicUri = serviceEndpoint.Address.Uri.AbsoluteUri;
                        WriteToLog(string.Format(ServiceHostListeningOnSubscription,
                                                 serviceEndpoint.ListenUri.AbsoluteUri));
                    }
                }

                // Start the service host
                serviceHost.Open();
                WriteToLog(ServiceHostSuccessfullyOpened);
            }
            catch (Exception ex)
            {
                mainForm.HandleException(ex);
            }
        }

        private void InternalWriteToLog(string message)
        {
            lock (this)
            {
                if (!string.IsNullOrEmpty(message))
                {
                    var lines = message.Split('\n');
                    var objNow = DateTime.Now;
                    var space = new string(' ', 19);

                    for (int i = 0; i < lines.Length; i++)
                    {
                        if (i == 0)
                        {
                            string line = string.Format(DateFormat,
                                                        objNow.Hour,
                                                        objNow.Minute,
                                                        objNow.Second,
                                                        lines[i]);
                            lstLog.Items.Add(line);
                        }
                        else
                        {
                            lstLog.Items.Add(space + lines[i]);
                        }
                    }
                    lstLog.SelectedIndex = lstLog.Items.Count - 1;
                    lstLog.SelectedIndex = -1;
                }
            }
        }

        private void SendRequestMessageUsingWCF(string endpointConfigurationName)
        {
            try
            {
                if (string.IsNullOrEmpty(endpointConfigurationName))
                {
                    WriteToLog(EndpointConfigurationNameCannotBeNull);
                    return;
                }

                // Set the wait cursor
                Cursor = Cursors.WaitCursor;

                // Make sure that the request message contains at least an operation
                if (operationList == null ||
                    operationList.Count == 0)
                {
                    WriteToLog(OperationListCannotBeNull);
                    return;
                }

                // Create warning collection
                var warningCollection = new List<string>();

                // Create request message
                var calculatorRequest = new CalculatorRequest(operationList);
                var calculatorRequestMessage = new CalculatorRequestMessage(calculatorRequest);

                // Create the channel factory for the currennt client endpoint
                // and cache it in the channelFactoryDictionary
                if (!channelFactoryDictionary.ContainsKey(endpointConfigurationName))
                {
                    channelFactoryDictionary[endpointConfigurationName] = new ChannelFactory<ICalculatorRequest>(endpointConfigurationName);
                }

                // Create the channel for the currennt client endpoint
                // and cache it in the channelDictionary
                if (!channelDictionary.ContainsKey(endpointConfigurationName))
                {
                    channelDictionary[endpointConfigurationName] = 
                        channelFactoryDictionary[endpointConfigurationName].CreateChannel();
                }

                // Use the OperationContextScope to create a block within which to access the current OperationScope
                using (new OperationContextScope((IContextChannel)channelDictionary[endpointConfigurationName]))
                {
                    // Create a new BrokeredMessageProperty object
                    var brokeredMessageProperty = new BrokeredMessageProperty();

                    // Read the user defined properties and add them to the  
                    // Properties collection of the BrokeredMessageProperty object
                    foreach (var e in propertiesBindingSource.Cast<PropertyInfo>())
                    {
                        try
                        {
                            e.Key = e.Key.Trim();
                            if (e.Type != StringType && e.Value == null)
                            {
                                warningCollection.Add(string.Format(CultureInfo.CurrentUICulture, 
                                                                    PropertyValueCannotBeNull, e.Key));
                            }
                            else
                            {
                                if (brokeredMessageProperty.Properties.ContainsKey(e.Key))
                                {
                                    brokeredMessageProperty.Properties[e.Key] = 
                                        ConversionHelper.MapStringTypeToCLRType(e.Type, e.Value);
                                }
                                else
                                {
                                    brokeredMessageProperty.Properties.Add(e.Key, 
                                        ConversionHelper.MapStringTypeToCLRType(e.Type, e.Value));
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            warningCollection.Add(string.Format(CultureInfo.CurrentUICulture, 
                                PropertyConversionError, e.Key, ex.Message));
                        }
                    }

                    // if the warning collection contains at least one or more items,
                    // write them to the log and return immediately
                    StringBuilder builder;
                    if (warningCollection.Count > 0)
                    {
                        builder = new StringBuilder(WarningHeader);
                        var warnings = warningCollection.ToArray<string>();
                        for (var i = 0; i < warningCollection.Count; i++)
                        {
                            builder.AppendFormat(WarningFormat, warnings[i]);
                        }
                        mainForm.WriteToLog(builder.ToString());
                        return;
                    }

                    // Set the BrokeredMessageProperty properties
                    brokeredMessageProperty.Label = txtLabel.Text;
                    brokeredMessageProperty.MessageId = Guid.NewGuid().ToString();
                    brokeredMessageProperty.SessionId = sessionId;
                    brokeredMessageProperty.ReplyToSessionId = sessionId;
                    brokeredMessageProperty.ReplyTo = responseQueueRadioButton.Checked
                                                     ? responseQueueUri
                                                     : responseTopicUri;
                    OperationContext.Current.OutgoingMessageProperties.Add(BrokeredMessageProperty.Name, 
                                                                           brokeredMessageProperty);
                    
                    // Send the request message to the requestqueue or requesttopic
                    var stopwatch = new Stopwatch();
                    try
                    {
                        stopwatch.Start();
                        channelDictionary[endpointConfigurationName].SendRequest(calculatorRequestMessage);
                    }
                    catch (CommunicationException ex)
                    {
                        if (channelFactoryDictionary[endpointConfigurationName] != null)
                        {
                            channelFactoryDictionary[endpointConfigurationName].Abort();
                            channelFactoryDictionary.Remove(endpointConfigurationName);
                            channelDictionary.Remove(endpointConfigurationName);
                        }
                        HandleException(ex);
                    }
                    catch (Exception ex)
                    {
                        if (channelFactoryDictionary[endpointConfigurationName] != null)
                        {
                            channelFactoryDictionary[endpointConfigurationName].Abort();
                            channelFactoryDictionary.Remove(endpointConfigurationName);
                            channelDictionary.Remove(endpointConfigurationName);
                        }
                        HandleException(ex);
                    }
                    finally
                    {
                        stopwatch.Stop();
                    }
                    // Log the request message and its properties
                    builder = new StringBuilder();
                    builder.AppendLine(string.Format(CultureInfo.CurrentCulture,
                            MessageSuccessfullySent,
                            channelFactoryDictionary[endpointConfigurationName].Endpoint.Address.Uri.AbsoluteUri,
                            brokeredMessageProperty.MessageId,
                            brokeredMessageProperty.SessionId,
                            brokeredMessageProperty.Label,
                            stopwatch.ElapsedMilliseconds));
                    builder.AppendLine(PayloadFormat);
                    for (var i = 0; i < calculatorRequest.Operations.Count; i++)
                    {
                        builder.AppendLine(string.Format(RequestFormat,
                                                         i + 1,
                                                         calculatorRequest.Operations[i].Operand1,
                                                         calculatorRequest.Operations[i].Operator,
                                                         calculatorRequest.Operations[i].Operand2));
                    }
                    builder.AppendLine(SentMessagePropertiesHeader);
                    foreach (var p in brokeredMessageProperty.Properties)
                    {
                        builder.AppendLine(string.Format(MessagePropertyFormat,
                                                         p.Key,
                                                         p.Value));
                    }
                    var traceMessage = builder.ToString();
                    WriteToLog(traceMessage.Substring(0, traceMessage.Length - 1));
                }
            }
            catch (Exception ex)
            {
                // Handle the exception
                HandleException(ex);
            }
            finally
            {
                // Restoire the defaulf cursor
                Cursor = Cursors.Default;
            }
        }

        #endregion

        #region Event Handlers

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void clearLogToolStripMenuItem_Click(object sender, EventArgs e)
        {
            lstLog.Items.Clear();
        }

        /// <summary>
        /// Saves the log to a text file
        /// </summary>
        /// <param name="sender">MainForm object</param>
        /// <param name="e">System.EventArgs parameter</param>
        private void saveLogToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (lstLog.Items.Count > 0)
                {
                    saveFileDialog.Title = SaveAsTitle;
                    saveFileDialog.DefaultExt = SaveAsExtension;
                    saveFileDialog.Filter = SaveAsFilter;
                    saveFileDialog.FileName = string.Format(LogFileNameFormat, DateTime.Now.ToString(CultureInfo.InvariantCulture).Replace('/', '-').Replace(':', '-'));
                    if (saveFileDialog.ShowDialog() == DialogResult.OK &&
                        !string.IsNullOrEmpty(saveFileDialog.FileName))
                    {
                        using (var writer = new StreamWriter(saveFileDialog.FileName))
                        {
                            foreach (var t in lstLog.Items)
                            {
                                writer.WriteLine(t as string);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }
        }

        private void logWindowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            splitContainer.Panel2Collapsed = !((ToolStripMenuItem)sender).Checked;
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var form = new AboutForm();
            form.ShowDialog();
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            try
            {
                if (queueRadioButton.Checked)
                {
                    SendRequestMessageUsingWCF("requestQueueClientEndpoint");
                    return;
                }
                if (topicRadioButton.Checked)
                {
                    SendRequestMessageUsingWCF("requestTopicClientEndpoint");
                }
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }
        }

        private void radioButton_CheckedChanged(object sender, EventArgs e)
        {
            groupBoxResponseMethod.Enabled = queueRadioButton.Checked || topicRadioButton.Checked;
        }

        private void lstLog_Leave(object sender, EventArgs e)
        {
            lstLog.SelectedIndex = -1;
        }
        #endregion
    }
}