August 25, 2011

MSMQ Integration Binding Service

Creating MSMQ Integration Binding Service with 3 different formatters


  • Binary Array - UTF 8 or UTF 16 messages 
  • Object 
  • XML

First add 3 non-transnational Message Queue's named below

  • testnetmsmq
  • testnetmsmqObject
  • testnetmsmqXElement
Add TestMsmqIntegration interface as below


  1. using System;
  2. using System.ServiceModel;
  3. using System.ServiceModel.MsmqIntegration;
  4. using System.Xml.Linq;
  5.  
  6. namespace TestMsmqIntegration
  7. {
  8.     // you can use one service (.svc) file however you need three separate interfaces
  9.     [ServiceContract(Namespace = "urn://MyTest/IntBindingService/ITestService/2013/11")]
  10.     public interface IMsmqIntService
  11.     {
  12.         [OperationContract(IsOneWay = true, Action = "*")]
  13.         [ServiceKnownType(typeof(Byte[]))]
  14.         void ProcessByteArrayMessage(MsmqMessage<Byte[]> mqMessage);
  15.     }
  16.  
  17.     [ServiceContract]
  18.     public interface IMsmqIntServiceObject
  19.     {
  20.         // USING OBJECT
  21.         [OperationContract(IsOneWay = true, Action = "*")]
  22.         [ServiceKnownType(typeof(SampleObject))]
  23.         void ProcessObjectMessage(MsmqMessage<SampleObject> mqMessage);
  24.     }
  25.  
  26.     [ServiceContract]
  27.     public interface IMsmqIntServiceXElement
  28.     {
  29.         // USING XElement
  30.         [OperationContract(IsOneWay = true, Action = "*")]
  31.         [ServiceKnownType(typeof(XElement))]
  32.         void ProcessXElementMessage(MsmqMessage<XElement> mqMessage);
  33.     }
  34. }


Add Service TestMsmqIntegration 


  1. using System;
  2. using System.Diagnostics;
  3. using System.ServiceModel.MsmqIntegration;
  4. using System.Text;
  5. using System.Xml.Linq;
  6.  
  7. namespace TestMsmqIntegration
  8. {
  9.     public class MsmqIntService : IMsmqIntService, IMsmqIntServiceObject, IMsmqIntServiceXElement
  10.     {
  11.         // byte[]> can also be used to get UTF-16 XML messages
  12.         public void ProcessByteArrayMessage(MsmqMessage<byte[]> mqMessage)
  13.         {
  14.             Debug.WriteLine("in1");
  15.             XElement xResponse = null;
  16.             var responseMessageBody = mqMessage.Body;
  17.             string responseMessageString;
  18.  
  19.             //load utf-16 message
  20.             try
  21.             {
  22.                 responseMessageString = Encoding.Unicode.GetString(responseMessageBody);
  23.                 xResponse = XElement.Parse(responseMessageString);
  24.             }
  25.             catch (Exception ex)
  26.             {
  27.                 //UTF-16 failed - try for UTF-8
  28.                 responseMessageString = Encoding.UTF8.GetString(responseMessageBody);
  29.                 xResponse = XElement.Parse(responseMessageString);
  30.             }
  31.  
  32.             // process message received from MQ
  33.             Console.WriteLine(xResponse.ToString());
  34.             Debug.WriteLine(xResponse.ToString());
  35.         }
  36.  
  37.         public void ProcessObjectMessage(MsmqMessage<SampleObject> mqMessage)
  38.         {
  39.             SampleObject so = (SampleObject)mqMessage.Body;
  40.             Debug.WriteLine(so.Name);
  41.         }
  42.  
  43.         public void ProcessXElementMessage(MsmqMessage<XElement> mqMessage)
  44.         {
  45.             XElement so = (XElement)mqMessage.Body;
  46.             Console.WriteLine(so.Value);
  47.         }
  48.     }
  49. }
Add Sample Object as below

  1. using System;
  2.  
  3. namespace TestMsmqIntegration
  4. {
  5.     [Serializable]
  6.     public class SampleObject
  7.     {
  8.         public int Id { get; set; }
  9.         public string Name { get; set; }
  10.     }
  11. }


Add Web.Config as below 


  1. <?xml version="1.0"?>
  2. <configuration>
  3.   <system.web>
  4.     <customErrors mode="Off" />
  5.     <compilation debug="true" targetFramework="4.5" />
  6.     <httpRuntime targetFramework="4.5" />
  7.   </system.web>
  8.   <system.serviceModel>
  9.     <behaviors>
  10.       <serviceBehaviors>
  11.         <behavior>
  12.           <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
  13.           <serviceDebug includeExceptionDetailInFaults="true"/>
  14.         </behavior>
  15.       </serviceBehaviors>
  16.     </behaviors>
  17.     <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  18.     <services>
  19.       <service name="TestMsmqIntegration.MsmqIntService"  >
  20.         <!--End point config to read message as byearray-->
  21.         <endpoint name="ByteArraySvc" address="msmq.formatname:DIRECT=OS:.\private$\testnetmsmq"
  22.                   binding="msmqIntegrationBinding" bindingConfiguration="IntQBind_ByteArray"
  23.                   contract="TestMsmqIntegration.IMsmqIntService"/>
  24.  
  25.         <!--End point config to read message as object-->
  26.         <endpoint name="ObjectSvc" address="msmq.formatname:DIRECT=OS:.\private$\testnetmsmqObject"
  27.                   binding="msmqIntegrationBinding" bindingConfiguration="IntQBind_Object"
  28.                   contract="TestMsmqIntegration.IMsmqIntServiceObject"/>
  29.  
  30.         <!--End point config to read message as XML-->
  31.         <endpoint name="XElementSvc" address="msmq.formatname:DIRECT=OS:.\private$\testnetmsmqXElement"
  32.                   binding="msmqIntegrationBinding" bindingConfiguration="IntQBind_Xelement"
  33.                   contract="TestMsmqIntegration.IMsmqIntServiceXElement"/>
  34.         <endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex"/>
  35.       </service>
  36.     </services>
  37.     <bindings>
  38.       <!--use exactlyOnce="true" if MQ is transactional-->
  39.       <!--binding config to read message as Byte array-->
  40.       <msmqIntegrationBinding>
  41.         <binding name="IntQBind_ByteArray" exactlyOnce="false" maxReceivedMessageSize="6553600" serializationFormat="ByteArray">
  42.           <security mode="None"/>
  43.         </binding>
  44.         <!--binding config to read message as object-->
  45.         <binding name="IntQBind_Object" exactlyOnce="false" maxReceivedMessageSize="6553600" >
  46.           <!--Note serializationFormat="Binary" won't work so do not specify any serializationFormat for object -->
  47.           <security mode="None"/>
  48.         </binding>
  49.         <!--binding config to read message as XML-->
  50.         <binding name="IntQBind_Xelement" exactlyOnce="false" maxReceivedMessageSize="6553600" serializationFormat="Xml">
  51.           <security mode="None"/>
  52.         </binding>
  53.         <!--More details on msmqmessageserializationformat-->
  54.         <!--https://msdn.microsoft.com/en-us/library/system.servicemodel.msmqintegration.msmqmessageserializationformat(v=vs.110).aspx-->
  55.       </msmqIntegrationBinding>
  56.     </bindings>
  57.   </system.serviceModel>
  58.   <system.webServer>
  59.     <!--Following config makes sure to init service automatically; may not work in local env-->
  60.     <!--<applicationInitialization doAppInitAfterRestart="true">
  61.       <add initializationPage="/MsmqIntService.svc"/>
  62.     </applicationInitialization>-->
  63.     <modules runAllManagedModulesForAllRequests="true"/>
  64.     <directoryBrowse enabled="true"/>
  65.   </system.webServer>
  66. </configuration>


Next add the following test client in Console program 


  1. using System.Messaging;
  2.  
  3. namespace TestMQConsole
  4. {
  5.     class Program
  6.     {
  7.         static void Main(string[] args)
  8.         {
  9.  
  10.             SendByteArray(@"<TestMQConsole>AJIT</TestMQConsole>", @".\private$\testnetmsmq");
  11.             SendObject(new SampleObject { Id = 1, Name = "Ajit" }, @".\private$\testnetmsmqobject");
  12.             SendXElement(@"<TestMQConsole>AJIT</TestMQConsole>", @".\private$\testnetmsmqxelement");
  13.         }
  14.  
  15.         public static void SendByteArray(object body, string queueName)
  16.         {
  17.             using (var queue = new MessageQueue(queueName))
  18.             {
  19.                 var logMessage = new Message { Body = body };
  20.                 queue.Send(logMessage);
  21.             }
  22.         }
  23.  
  24.         public static void SendObject(SampleObject so, string queueName)
  25.         {
  26.             using (var queue = new MessageQueue(queueName))
  27.             {
  28.                 var logMessage = new Message(so);
  29.                 queue.Send(logMessage);
  30.             }
  31.         }
  32.  
  33.         public static void SendXElement(string xml, string queueName)
  34.         {
  35.             using (var queue = new MessageQueue(queueName))
  36.             {
  37.                 var logMessage = new Message { Body = xml };
  38.                 queue.Send(logMessage);
  39.             }
  40.         }
  41.     }
  42. }


Note that to send object you also need sample object at client side 


  1. using System;
  2. namespace TestMQConsole
  3. {
  4.     [Serializable]
  5.     public class SampleObject
  6.     {
  7.         public int Id { get; set; }
  8.         public string Name { get; set; }
  9.     }
  10. }


Important points to note: 
  • You can use one service (.svc) file however you need three separate interfaces 
  • Remove comments from Web.Config file for the following code to activate service automatically so it can continuously listen MQ; 
  • Use exactlyOnce="true" in web.config file (binding) if MQ is transactional 
  • byte[] can also be used to get UTF-16 XML messages Below is Web.config file w/o encoding