WCF:“为MTOM消息创建阅读器时出错”

试图让MTOM在WCF客户端中工作。 我正在尝试使用的特定函数发送一个PDF文档的MTOM编码字节数组。 使用SoapUI使用WSDL测试API工作正常; 但是,当我尝试在客户端中执行相同的操作时,我收到以下错误:

Error creating a reader for the MTOM message System.Xml.XmlException: MTOM messages must have type 'application/xop+xml'. at System.Xml.XmlMtomReader.ReadMessageContentTypeHeader(ContentTypeHeader he ader, String& boundary, String& start, String& startInfo) at System.Xml.XmlMtomReader.Initialize(Stream stream, String contentType, Xml DictionaryReaderQuotas quotas, Int32 maxBufferSize) at System.Xml.XmlMtomReader.SetInput(Stream stream, Encoding[] encodings, Str ing contentType, XmlDictionaryReaderQuotas quotas, Int32 maxBufferSize, OnXmlDic tionaryReaderClose onClose) at System.Xml.XmlMtomReader.SetInput(Byte[] buffer, Int32 offset, Int32 count , Encoding[] encodings, String contentType, XmlDictionaryReaderQuotas quotas, In t32 maxBufferSize, OnXmlDictionaryReaderClose onClose) at System.Xml.XmlDictionaryReader.CreateMtomReader(Byte[] buffer, Int32 offse t, Int32 count, Encoding[] encodings, String contentType, XmlDictionaryReaderQuo tas quotas, Int32 maxBufferSize, OnXmlDictionaryReaderClose onClose) at System.ServiceModel.Channels.MtomMessageEncoder.MtomBufferedMessageData.Ta keXmlReader() Server stack trace: at System.ServiceModel.Channels.MtomMessageEncoder.MtomBufferedMessageData.Ta keXmlReader() at System.ServiceModel.Channels.BufferedMessageData.DoTakeXmlReader() at System.ServiceModel.Channels.BufferedMessageData.GetMessageReader() at System.ServiceModel.Channels.BufferedMessage..ctor(IBufferedMessageData me ssageData, RecycledMessageState recycledMessageState, Boolean[] understoodHeader s, Boolean understoodHeadersModified) at System.ServiceModel.Channels.BufferedMessage..ctor(IBufferedMessageData me ssageData, RecycledMessageState recycledMessageState) at System.ServiceModel.Channels.MtomMessageEncoder.ReadMessage(ArraySegment`1 buffer, BufferManager bufferManager, String contentType) at System.ServiceModel.Channels.MessageEncoder.ReadMessage(Stream stream, Buf ferManager bufferManager, Int32 maxBufferSize, String contentType) at System.ServiceModel.Channels.HttpInput.ReadChunkedBufferedMessage(Stream i nputStream) at System.ServiceModel.Channels.HttpInput.ParseIncomingMessage(Exception& req uestException) at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpCha nnelRequest.WaitForReply(TimeSpan timeout) at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeS pan timeout) at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message messag e, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean on eway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan tim eout) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean on eway, ProxyOperationRuntime operation, Object[] ins, Object[] outs) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCall Message methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) Exception rethrown at [0]: at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage req Msg, IMessage retMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgDa ta, Int32 type) at WsApiServicePortType.getDoc(getDocRequest request) at WsApiServicePortTypeClient.WsApiServicePortType.getDoc(getDocReq uest request) in C:\Users\ant\documents\visual studio 2010\Projects\Client\Cl ient\WsApiService.cs:line 3927 at WsApiServicePortTypeClient.getDoc(String username, String ID) in C :\Users\ant\documents\visual studio 2010\Projects\Client\Client\WsApiServic e.cs:line 3935 at Client.Program.Main(String[] args) in C:\Users\ant\documents\visual stu dio 2010\Projects\Client\Client\Program.cs:line 18 

现在,我已经搜索了全部,并且找不到与此错误相关的内容,除非是这样: http : //social.msdn.microsoft.com/Forums/en-US/wcf/thread/73039d75-e078-436b -a8ab-d8c7197a976b

但是,该链接中的建议对我没有意义。 我在代码中的任何地方都看不到响应消息作为我可以修改它的对象存在。 所以……我在这里。 我拥有的客户端非常简单:它由svcutil生成的代理类组成,约。 调用10行代码和app.config文件。 我已将证书信息添加到配置文件并将messageEncoding更改为Mtom,但除此之外,它都是由svcutil生成的。

这是客户端代码的样子(非常简单,如您所见):

 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.ServiceModel; using System.Text; namespace Client { class Program { static void Main(string[] args) { try { WsApiServicePortTypeClient client = new WsApiServicePortTypeClient(); byte[] doc = client.getRecordDoc("username0000", "1234567"); File.WriteAllBytes(@"C:\TestRecords\wcf-test.pdf", doc); Console.WriteLine("Ok, check it now."); Console.ReadLine(); } catch (Exception ex) { Console.WriteLine("ERROR: " + ex.Message + Environment.NewLine + ex.GetBaseException().ToString() + Environment.NewLine + ex.StackTrace + Environment.NewLine); Console.ReadLine(); } } } } 

从代理类:

 [assembly: System.Runtime.Serialization.ContractNamespaceAttribute("http://www..com/ws/schemas", ClrNamespace="www..com.ws.schemas")] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] [System.ServiceModel.ServiceContractAttribute(Namespace="http://www..com/ws/definitions", ConfigurationName="WsApiServicePortType")] public interface WsApiServicePortType { ... // CODEGEN: Generating message contract since the wrapper namespace (http://www..com/ws/schemas) of message getRecordDocRequest does not match the default value (http://www..com/ws/definitions) [System.ServiceModel.OperationContractAttribute(Action="http://localhost:8080/getRecordDoc", ReplyAction="http://www..com/ws/definitions/WsApiServicePortType/getRecordDocResponse")] [System.ServiceModel.FaultContractAttribute(typeof(www..com.ws.schemas.fault), Action="http://www..com/ws/definitions/WsApiServicePortType/getRecordDoc/Fault/wsFault", Name="fault", Namespace="http://www..com/ws/schemas")] [System.ServiceModel.XmlSerializerFormatAttribute()] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(wsError))] getRecordDocResponse getRecordDoc(getRecordDocRequest request); ... } [System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] public partial class WsApiServicePortTypeClient : System.ServiceModel.ClientBase, WsApiServicePortType { public WsApiServicePortTypeClient() { } public WsApiServicePortTypeClient(string endpointConfigurationName) : base(endpointConfigurationName) { } public WsApiServicePortTypeClient(string endpointConfigurationName, string remoteAddress) : base(endpointConfigurationName, remoteAddress) { } public WsApiServicePortTypeClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress) { } public WsApiServicePortTypeClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(binding, remoteAddress) { } ... [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] getRecordDocResponse WsApiServicePortType.getRecordDoc(getRecordDocRequest request) { return base.Channel.getRecordDoc(request); } public byte[] getRecordDoc(string username, string ID) { getRecordDocRequest inValue = new getRecordDocRequest(); inValue.username = username; inValue.ID = ID; getRecordDocResponse retVal = ((WsApiServicePortType)(this)).getRecordDoc(inValue); return retVal.doc; } ... } 

从app.config:

                         <endpoint address="https://wisp..com/services/WsApiService/" behaviorConfiguration="NewBehavior0" binding="basicHttpBinding" bindingConfiguration="WsApiServiceSoapBinding" contract="WsApiServicePortType" name="WsApiServicePort" />    

此外,虽然我在粘贴之前将其从配置文件中删除,但我已将其配置为用于消息跟踪和日志记录,并且这是记录的内容:

出站:

   POST   gibberish     http://localhost:8080/getRecordDoc urn:uuid:19966f2b-b5ed-4e30-8bd9-9180fbf527bf 95e158bd-51e7-4fe6-900b-642728f0653e  http://www.w3.org/2005/08/addressing/anonymous  https://www..com/services/WsApiService/   <getRecordDoc xmlns="http://www..com/ws/schemas"> username0000 1234567     

以下是回复:

 <![CDATA[ --MIMEBoundaryurn_uuid_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Content-Type: text/xml; charset=UTF-8 Content-Transfer-Encoding: binary Content-ID:   <ns1:getRecordDocResponse xmlns:ns1="http://www..com/ws/schemas"> --MIMEBoundaryurn_uuid_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Content-Type: application/octet-stream Content-Transfer-Encoding: binary Content-ID:  %PDF-1.5 (blah blah blah Wingdings!) --MIMEBoundaryurn_uuid_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-- ]]> 

跟踪日志显示“Construct ChannelFactory”和“Open ClientBase”步骤已成功完成,但是当它尝试“Process action http://localhost:8080/getRecordDoc ,它在启动活动边界后失败,如下所示:

   131075 3 0 2      computer      http://msdn.microsoft.com/en-US/library/System.ServiceModel.Diagnostics.ThrowingException.aspx Throwing an exception. Client.vshost.exe  System.ServiceModel.CommunicationException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=publickeytokeninfo Error creating a reader for the MTOM message  at System.ServiceModel.Channels.MtomMessageEncoder.MtomBufferedMessageData.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, Boolean understoodHeadersModified) at System.ServiceModel.Channels.BufferedMessage..ctor(IBufferedMessageData messageData, RecycledMessageState recycledMessageState) at System.ServiceModel.Channels.MtomMessageEncoder.ReadMessage(ArraySegment`1 buffer, BufferManager bufferManager, String contentType) at System.ServiceModel.Channels.MessageEncoder.ReadMessage(Stream stream, BufferManager bufferManager, Int32 maxBufferSize, String contentType) at System.ServiceModel.Channels.HttpInput.ReadChunkedBufferedMessage(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.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.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) at WsApiServicePortType.getRecordDoc(getRecordDocRequest request) at WsApiServicePortTypeClient.WsApiServicePortType.getRecordDoc(getRecordDocRequest request) at WsApiServicePortTypeClient.getRecordDoc(String username, String stiId) at Client.Program.Main(String[] args) at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart()  System.ServiceModel.CommunicationException: Error creating a reader for the MTOM message ---> System.Xml.XmlException: MTOM messages must have type 'application/xop+xml'. at System.Xml.XmlMtomReader.ReadMessageContentTypeHeader(ContentTypeHeader header, String& boundary, String& start, String& startInfo) 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.XmlMtomReader.SetInput(Byte[] buffer, Int32 offset, Int32 count, 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() --- End of inner exception stack trace ---  System.Xml.XmlException, System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=publickeytokeninfo MTOM messages must have type 'application/xop+xml'.  at System.Xml.XmlMtomReader.ReadMessageContentTypeHeader(ContentTypeHeader header, String& boundary, String& start, String& startInfo) 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.XmlMtomReader.SetInput(Byte[] buffer, Int32 offset, Int32 count, 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()  System.Xml.XmlException: MTOM messages must have type 'application/xop+xml'. at System.Xml.XmlMtomReader.ReadMessageContentTypeHeader(ContentTypeHeader header, String& boundary, String& start, String& startInfo) 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.XmlMtomReader.SetInput(Byte[] buffer, Int32 offset, Int32 count, 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()        

我认为这与合同包装器有关,如代理类文件中的CODEGEN消息所示。 但是,我无法找到有关该消息的任何信息,这可以证实这一点。

任何帮助是极大的赞赏。

更新:正如@Tone在评论中提到的那样,下面原来接受的答案是错误的。 实际上,有效(并且需要)MTOM HTTP响应头的外部Content-Type具有值“multipart / related”。 这是原始海报收到的标题:

 Content-Type multipart/related; boundary="MIMEBoundaryurn_uuid_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"; start-info="text/xml"; type="text/xml"; start="<0.urn:uuid:xxxxxxxxxxxxxxxxxxxxxxxxxxxx@apache.org>" 

真正的问题似乎是“type”属性是“text / xml”而不是“application / xop + xml”。

==============================================

原始答案:

这里的Content-Type标题是“multipart / related”。 这不是发送MTOM响应的正确标头,所以我认为这是服务器错误。 正如例外所述,“MTOM消息必须具有(内容)类型’application / xop + xml’”。 尝试在服务器上对其进行硬编码,或者在某些代理中暂时更改它以查看wcf是否可行(您也可以尝试使用wcf自定义消息编码器,应该覆盖一个属性 – ContentType – 返回正确的类型)。 请注意,存在二进制有效负载(文件附件)标准,允许内容类型为“multipart / related”但wcf不支持它们。 但是在这里消息有效负载使用标签,所以我相信服务器确实意味着发送mtom但不使用正确的内容类型标头。

BTW 这里是我为wcf提到的其他附件标准的实现 。 它可能对你有用,pdf将在某些属性中提供。 但另一方面,因为xml使用它可能无效,所以你可能需要在编码器中调整它。 所以最好是解决服务器中的根问题。

对于我的情况,我得到了指示的错误,在我的绑定中

 maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" 

直到我补充说它才开始工作:

 maxBufferSize="2147483647" 

只是因为任何人都有同样的问题。