Wednesday, 15 June 2011

Duet Enterprise Integration - Fix for "System.ArgumentException: An item with the same key has already been added due to Extra Content Type Headers" in SharePoint 2010 ULS Logs

If you're not aware, Duet Enterprise ( is an integration framework and infrastructure for providing SAP to SharePoint integration - of task lists, SAP workflows, SAP reports, SAP security and SAP data (through SharePoint BCS).

I recently had an issue with a Duet Enterprise deployment for one of my clients. When retrieving data, the out of the box web parts were failing and dropping the following Exception in the SharePoint 2010 ULS Logs:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentException: An item with the same key has already been added. Server stack trace:
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
at System.Xml.ContentTypeHeader.ParseValue()
at System.Xml.ContentTypeHeader.get_MediaType()
at System.Xml.XmlMtomReader.ReadRootContentTypeHeader(ContentTypeHeader header, Encoding[] expectedEncodings, String expectedType)
at System.Xml.XmlMtomReader.Initialize(Stream stream, String contentType, XmlDictionaryReaderQuotas quotas, Int32 maxBufferSize)
at System.Xml.XmlMtomReader.SetInput(Stream stream, Encoding[] encodings, String contentType, XmlDictionaryReaderQuotas quotas, Int32 maxBufferSize, OnXmlDictionaryReaderClose onClose)
at System.Xml.XmlDictionaryReader.CreateMtomReader(Byte[] buffer, Int32 offset, Int32 count, Encoding[] encodings, String contentType, XmlDictionaryReaderQuotas quotas, Int32 maxBufferSize, OnXmlDictionaryReaderClose onClose)
at System.ServiceModel.Channels.MtomMessageEncoder.MtomBufferedMessageData.TakeXmlReader()
at System.ServiceModel.Channels.BufferedMessageData.GetMessageReader()
at System.ServiceModel.Channels.BufferedMessage..ctor(IBufferedMessageData messageData, RecycledMessageState recycledMessageState, Boolean[] understoodHeaders)
at System.ServiceModel.Channels.MtomMessageEncoder.ReadMessage(ArraySegment`1 buffer, BufferManager bufferManager, String contentType)
at System.ServiceModel.Channels.HttpInput.DecodeBufferedMessage(ArraySegment`1 buffer, Stream inputStream)
at System.ServiceModel.Channels.HttpInput.ReadBufferedMessage(Stream inputStream)
at System.ServiceModel.Channels.HttpInput.ParseIncomingMessage(Exception& requestException)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)

at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) 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 BCSServiceProxy.IWXManageCustomerIn.FindCustomerByElements(FindCustomerByElementsRequest request)
at BCSServiceProxy.WXManageCustomerInClient.BCSServiceProxy.IWXManageCustomerIn.FindCustomerByElements(FindCustomerByElementsRequest request)
at BCSServiceProxy.WXManageCustomerInClient.FindCustomerByElements(BPCCustGetAll BPCCustGetAll) -

-- End of inner exception stack trace ---
at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at Microsoft.SharePoint.BusinessData.SystemSpecific.Wcf.WcfSystemUtility.Execute(Object[] args)

I immediately thought that it was something wrong with the data. Because Duet uses HTTPS & SSL for all communications between SAP Netweaver 7.02+ and SharePoint 2010, I had to decrypt the traffic to work out what was going on. Running the calls on the SAP site returned blank results. To get WireShark ( decrypting the traffic we had to generate a certificate in SAP with a private key. We had to get the key out in PKCS#12 format and then convet it to the .PEM format that wireshark accepts - similar to what is desribed here:
We used "sapgenpse" in SAP to generate the certificate with the private key - as per the screenshot below:
Once the key was set in WireShark preferences, you will see many of the packets being processed being marked as green. You can then right click on them and choose "Follow SSL Stream" on your web request - and you will see the decrypted version of your HTTPS traffic.

Turns out, the issue was with SAP retuning duplicate Content headers in the response to SharePoint BCS (as per the screenshot).

There is a SAP Note to fix this very issue - "SAP Note 1539888 - Composite Note -Duet Enterprise Installation Wizard". You will need a SAP Service Market place to log on to get this note.


1 comment:

Maxim said...

Thanks a lot for your post.
I have the same issue.
My problem is I'm a SharePoint guy and not familiar with SAP.
If this resolution helps - you safe me a day..