Sending a PUT to a RESTful (REST) service using BizTalk 2006R2

Posted: June 12, 2011  |  Categories: BizTalk Uncategorized

Recently I had to finish a project another one of my colleagues. He had created a nice solution that was sending messages to a RESTful service but sometimes when he submitted a PUT request the following error was written to the event viewer;

A message sent to adapter “WCF-Custom” on send port “TestRestSendPort” with URI http://app.com/api/2.0/jobs/20110504762714.xml?user_credentials=*************&use_third_party_id=true is suspended.
Error details: System.ServiceModel.ProtocolException: There is a problem with the XML that was received from the network. See inner exception for more details. —> System.Xml.XmlException: Unexpected end of file.
at System.Xml.EncodingStreamWrapper.ProcessBuffer(Byte[] buffer, Int32 offset, Int32 count, Encoding encoding)
at System.Xml.XmlUTF8TextReader.SetInput(Byte[] buffer, Int32 offset, Int32 count, Encoding encoding, XmlDictionaryReaderQuotas quotas, OnXmlDictionaryReaderClose onClose)
at System.Xml.XmlDictionaryReader.CreateTextReader(Byte[] buffer, Int32 offset, Int32 count, Encoding encoding, XmlDictionaryReaderQuotas quotas, OnXmlDictionaryReaderClose onClose)
at System.ServiceModel.Channels.TextMessageEncoderFactory.TextMessageEncoder.UTF8BufferedMessageData.TakeXmlReader()
at System.ServiceModel.Channels.BufferedMessageData.DoTakeXmlReader()
at System.ServiceModel.Channels.BufferedMessageData.GetMessageReader()
at System.ServiceModel.Channels.BufferedMessage..ctor(IBufferedMessageData messageData, RecycledMessageState recycledMessageState, Boolean[] understoodHeaders)
at System.ServiceModel.Channels.TextMessageEncoderFactory.TextMessageEncoder.ReadMessage(ArraySegment`1 buffer, BufferManager bufferManager, String contentType)
at System.ServiceModel.Channels.HttpInput.DecodeBufferedMessage(ArraySegment`1 buffer, Stream inputStream)
— End of inner exception stack trace —

Server stack trace:
at System.ServiceModel.AsyncResult.End[TAsyncResult](IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.EndRequest(IAsyncResult result)

Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at System.ServiceModel.Channels.IRequestChannel.EndRequest(IAsyncResult result)
at Microsoft.BizTalk.Adapter.Wcf.Runtime.WcfClient`2.RequestCallback(IAsyncResult result)

Why were we getting an error because the PUT was successfully executed on the RESTful service?

The solution sends message request to  a dynamic port configured as a  WCF-Custom adapter and has a custom behaviour to help create the RESTful request. This approach has been described before at these links; http://social.technet.microsoft.com/wiki/contents/articles/invoking-restful-web-services-with-biztalk-server-2010.aspx, http://social.msdn.microsoft.com/Forums/en-US/biztalkesb/thread/c19d7486-0705-433f-8e1a-a9088d076ed7 and http://codemonkeyseedo.blogspot.com/2011/05/biztalk-to-wcf-data-services-part-2-wcf.html.

The first thing that i tried to do was to trace the response message coming back from the RESTful service. After several false starts I discovered that there was no message. The error has occurred because XML parser has tried to parse an empty SOAP response. My initial thought was that the RESTful service should not be sending a blank message back when when the PUT was successful. After reflection I realised that the RESTful service was behaving correctly and it was only our BizTalk implementation that was not handing this situation correctly.

I solved the problem by creating a custom text message encoder that first checked for a blank response before sending the response to the XML parser. If a blank response is found then we replace it with a default XML response.

CustomTextMessageEncoder

The custom text message encoder was based on this example http://msdn.microsoft.com/en-us/library/ms751486(v=VS.85).aspx.  I modified the ReadMessage method as shown below;

public override Message ReadMessage(Stream
stream, int maxSizeOfHeaders, string contentType)

        {

            XmlReader reader;

System.Diagnostics.Trace.Write(“[Datacom.WCF.Custom.TextMessageEncoder4REST.Message].Start
Stream length = ” +  stream.Length);

            if (stream.Length <= 1)

            {

System.Diagnostics.Trace.Write(“[Datacom.WCF.Custom.TextMessageEncoder4REST.Message].Start”);

reader = XmlReader.Create(new StringReader(this.MsgXMLOverride));

            }

            else

            {

                reader = XmlReader.Create(stream);

            }

            return Message.CreateMessage(reader,
maxSizeOfHeaders, this.MessageVersion);

        }

Once the custom text message encoder was configured on the dynamic port , an error message is no longer written to the event viewer on a successful PUT to the RESTful service. Thanks Craig.

turbo360

Back to Top