BizTalk and the WCF Channel for WebSphere MQ

This post is about how to (or not how to – more of that later) use the WCF Channel for WebSphere MQ with BizTalk.

WCF Channel for WebSphere MQ is part of BizTalk Adapters for Host Systems (BAHS) 2.0. (On MSDN subscriber downloads, it is listed under BizTalk Server 2009. In MSDN library, the product documentation is listed under Host Integration Server 2009.) During installation, check this component:

image

To be able to use the new WCF channel, a new channel binding must be defined in Machine.config (in C:WindowsMicrosoft.NETFrameworkv2.0.50727CONFIG). Under <system.serviceModel><extensions><bindingExtensions> add

<add name="mqChannelBinding" type="System.ServiceModel.Channels.WebSphereMQ.WebSphereMQBindingCollectionElement, System.ServiceModel.Channels.WebSphereMQ.Channel, Version=7.0.2300.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

(For details, see How to Enable the WCF Extensibility Points with the WCF Adapters.)

To be able to test, I installed an evaluation copy of WebSphere MQ 7.0, which I downloaded from IBM. (Registration is necessary.) During installation, include MQ Explorer – it is handy for troubleshooting. During configuration, I used the following options:

image

The installation was performed on a Windows 2008 server called BTS2009. This installation created a queue manager called QM_BTS2009, a channel called S_BTS2009 and a listener on port 1414.

Next, create a send port in BizTalk, choose transport type WCF-Custom and click Configure. On the general tab, the address (URI) should be net.mqs://<queue manager name>/<queue name>, e.g. net.mqs://QM_BTS2009/default. On the Binding tab, select mqChannelBinding and input the appropriate configuration:

Key Value Example
connectionType BaseClient BaseClient
deadLetterQuee True True
leaveMQHeadersInMessage True True
mqcdChannelName <channel name> S_BTS2009
mqcdConnectionName <host>(<port>) BTS2009(1414)
mqcdTransportType TCP TCP

Or import this configuration file if you don’t want to type so much:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <enterpriseLibrary.ConfigurationSource selectedSource="ESB File Configuration Source" />
  <system.serviceModel>
    <client>
      <endpoint address="net.mqs://QM_BTS2009/default" behaviorConfiguration="EndpointBehavior" binding="mqChannelBinding" bindingConfiguration="SendSampleBinding" contract="BizTalk" name="ToMQSeries" />
    </client>
    <behaviors>
      <endpointBehaviors>
        <behavior name="EndpointBehavior" />
      </endpointBehaviors>
    </behaviors>
    <bindings>
      <mqChannelBinding>
        <binding name="SendSampleBinding" connectionType="BaseClient" leaveMQHeadersInMessage="True" deadLetterQueue="True" mqcdChannelName="S_BTS2009" mqcdTransportType="TCP" mqcdConnectionName="BTS2009(1414)" mqpmoSyncPoint="True" mqgmoSyncPoint="True">
          <readerQuotas maxDepth="10" maxArrayLength="1000" maxBytesPerRead="2000" />
        </binding>
      </mqChannelBinding>
    </bindings>
  </system.serviceModel>
</configuration>

Now send an XML document to this send port and check the result in WebSphere MQ Explorer. The queue depth should be 1.

So what about receiving a message from MQ? I tested that too, but had issues. Using the following configuration:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <enterpriseLibrary.ConfigurationSource selectedSource="ESB File Configuration Source" />
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="SendReceiveSampleServiceBehaviour" name="BizTalk">
        <endpoint address="net.mqs://QM_BTS2009/default" behaviorConfiguration="EndpointBehavior" binding="mqChannelBinding" bindingConfiguration="SendReceiveSampleBinding" name="FromMQSeries2" contract="BizTalk" />
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="EndpointBehavior" />
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="SendReceiveSampleServiceBehaviour" />
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <mqChannelBinding>
        <binding name="SendReceiveSampleBinding" connectionType="BaseClient" leaveMQHeadersInMessage="True" deadLetterQueue="True" mqcdChannelName="S_BTS2009" mqcdTransportType="TCP" mqcdConnectionName="BTS2009(1414)" mqpmoSyncPoint="True" mqgmoSyncPoint="True">
          <readerQuotas maxDepth="10" maxArrayLength="1000" maxBytesPerRead="2000" />
        </binding>
      </mqChannelBinding>
    </bindings>
  </system.serviceModel>
</configuration>

I got the following warning repeatedly in the application event log:

Event Type:    Warning
Event Source:    BizTalk Server 2009
Event Category:    (1)
Event ID:    5740
Date:        2009-08-25
Time:        15:24:07
User:        N/A
Computer:    BTS2009
Description:
The adapter "WCF-Custom" raised an error message. Details "System.ServiceModel.Channels.WebSphereMQ.WebSphereMQException: Unexpected error; webspheremqtransport.cpp#1206; ImqQueueManager::connect; completionCode = 2; reasonCode = 2058
   at System.ServiceModel.Channels.WebSphereMQ.AsyncResult.End[TAsyncResult](IAsyncResult result)
   at System.ServiceModel.Channels.WebSphereMQ.TryReceiveAsyncResult.End(IAsyncResult result, Message& message)
   at System.ServiceModel.Channels.WebSphereMQ.WebSphereMQInputChannel.EndTryReceive(IAsyncResult result, Message& message)
   at System.ServiceModel.Dispatcher.InputChannelBinder.EndTryReceive(IAsyncResult result, RequestContext& requestContext)
   at System.ServiceModel.Dispatcher.ErrorHandlingReceiver.EndTryReceive(IAsyncResult result, RequestContext& requestContext)".

The message was not read. The strange thing is that I could get it to work with the MQSC (client based) adapter. I could also run the BAHS SendReceiveSample .Net sample without errors.

Supposedly the cause is that BizTalk uses System.URI which appears to convert everything to lower case, and since MQ is case sensitive, it does not work. So until this bug is fixed, you have to use queue manager and queue names in lower case.

In my case, I created a new queue manager called qm_test with a listener listening on port 1415. I then created a queue called q_test and a channel called S_BTS2009 as before. I then adjusted the send port and receive location configurations. That worked!

Advertisements

2 thoughts on “BizTalk and the WCF Channel for WebSphere MQ”

  1. Good article, I could not find a whole lot on the MQ channel in the HIS 2009 documents so this was invaluable thanks.By chance do you know if it is possible to configure the adapter to suspend invalid messages inside BizTalk? I keep getting the following error with no suspended message if the message is say invalid XML. The message just disappears or is left on the Websphere MQ queue.Event Type: WarningEvent Source: BizTalk Server 2009Event Category: (1)Event ID: 5740Date: 22/01/2010Time: 11:38:34 a.m.User: N/AComputer: Description:The adapter "WCF-Custom" raised an error message. Details "System.Xml.XmlException: The data at the root level is invalid. Line 1, position 1. at System.Xml.XmlExceptionHelper.ThrowXmlException(XmlDictionaryReader reader, String res, String arg1, String arg2, String arg3) at System.Xml.XmlUTF8TextReader.Read() at System.Xml.XmlBaseReader.MoveToContent() at System.ServiceModel.Channels.StreamedMessage..ctor(XmlDictionaryReader reader, Int32 maxSizeOfHeaders, MessageVersion desiredVersion) at System.ServiceModel.Channels.Message.CreateMessage(XmlDictionaryReader envelopeReader, Int32 maxSizeOfHeaders, MessageVersion version) at System.ServiceModel.Channels.TextMessageEncoderFactory.TextMessageEncoder.ReadMessage(Stream stream, Int32 maxSizeOfHeaders, String contentType) at System.ServiceModel.Channels.MessageEncoder.ReadMessage(Stream stream, Int32 maxSizeOfHeaders) at System.ServiceModel.Channels.WebSphereMQ.MQTransport.TryReceive(TimeSpan timeout, Message& message, IMQNotifier& notifier, Byte[]& messageCorrelationId) at System.ServiceModel.Channels.WebSphereMQ.WebSphereMQInputChannel.TryReceive(TimeSpan timeout, Message& message) at System.ServiceModel.Dispatcher.InputChannelBinder.TryReceive(TimeSpan timeout, RequestContext& requestContext) at System.ServiceModel.Dispatcher.ErrorHandlingReceiver.TryReceive(TimeSpan timeout, RequestContext& requestContext)".For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.

  2. It seems like this error is from WCF and that the message hasn’t reached BizTalk, hence I don’t think the message can be suspended inside BizTalk. Is the message really XML? Which encoding? Try with an XML file that is UTF-8 encoded.

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s