WCF:元素已导出错误

时间:2011-09-20 23:05:17

标签: wcf

我从原始帖子中获得了更多信息,并且能够在一个非常简单的文件中重新创建问题>新项目> WCF服务应用解决方案。因此,我正在大量编辑这篇文章的原始内容,以摆脱一些多余的信息并简化示例:

我们的消息合约定义如下。

[MessageContract( WrapperName = "SingleTypeResponse", WrapperNamespace = "urn:WcfService1" )]
public class SingleTypeResponse<T>
{
    [MessageBodyMember( Name = "ReturnValue" )]
    public T ReturnValue { get; set; }
}

服务界面具有以下内容:

[OperationContract]
SingleTypeResponse<string> GetStringData();

[OperationContract]
SingleTypeResponse<int> GetIntData();

当我运行项目并导航到.svc文件时,我得到以下内容:

调用WSDL导出扩展时抛出异常:System.ServiceModel.Description.DataContractSerializerOperationBehavior  合同:http://tempuri.org/:IService1 ----&gt; System.InvalidOperationException:WcfService1.IService1.GetIntData操作引用已从WcfService1.IService1.GetStringData操作导出的消息元素[urn:WcfService1:SingleTypeResponse]。您可以通过更改方法名称或使用OperationContractAttribute的Name属性来更改其中一个操作的名称。或者,您可以使用MessageContract编程模型更详细地控制元素名称。

如果我在接口上注释掉GetIntData并使用WCF测试客户端测试服务,并设置了WrapperName属性,我会得到以下响应XML:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header />
  <s:Body>
    <SingleTypeResponse xmlns="urn:WcfService1">
      <ReturnValue xmlns="http://tempuri.org/">foo</ReturnValue>
    </SingleTypeResponse>
  </s:Body>
</s:Envelope>

我猜这个元素是问题的根源,它看到同一个元素的两个版本,一个带字符串,一个带有int。

然后我取消注释GetIntData并从MessageContract中删除了WrapperName属性:

[MessageContract( WrapperNamespace = "urn:WcfService1" )]
public class SingleTypeResponse<T>
{
    [MessageBodyMember( Name = "ReturnValue" )]
    public T ReturnValue { get; set; }
}

我收到与相同的错误消息,它抱怨的消息元素是合约的ReturnValue属性而不是消息合约名称。

再次评论GetIntData并使用WCF测试客户端进行测试我得到:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header />
  <s:Body>
    <SingleTypeResponseOf_String xmlns="urn:WcfService1">
      <ReturnValue xmlns="http://tempuri.org/">foo</ReturnValue>
    </SingleTypeResponseOf_String>
  </s:Body>
</s:Envelope>

所以我能够让它为包装器创建一个唯一的名称,但SingleTypeResponseOf_String和SingleTypeResponseOf_Int32都具有ReturnValue属性这一事实继续导致它的大脑爆发。

1 个答案:

答案 0 :(得分:3)

我以前从未考虑过它,但是有必要将泛型类型定义为WSDL的具体类型。从这个角度来看,似乎是 - 您在服务中定义了SingleTypeResponse的两种“类型”。 WSDL不允许同名的两个元素定义&amp;命名空间共存(出于显而易见的原因 - 它们需要是唯一可识别的)。

这里有几个潜在的冲突。我想你已经确定了第一个 - SingleTypeResponse命名空间中名为urn:WcfService1的元素。当您关闭消息合约的命名(允许它由序列化程序命名)时,您会看到以下内容:

<!-- Setting wrapper name & wrapper namespace -->
<wsdl:message name="SingleTypeResponseOf_String">
  <wsdl:part name="parameters" element="q1:SingleTypeResponse" 
             xmlns:q1="urn:WcfService1" /> 
</wsdl:message>

<!-- Setting wrapper namespace only -->
<wsdl:message name="SingleTypeResponseOf_String">
  <wsdl:part name="parameters" element="q1:SingleTypeResponseOf_String" 
             xmlns:q1="urn:WcfService1" /> 
</wsdl:message>

这应避免第一次冲突,因为运行两项操作意味着您将能够拥有两种类型的元素(SingleTypeResponseOf_StringSingleTypeResponseOf_Int)。

我相信你的第二个冲突来自MessageBodyMember属性。因为两个操作都在同一名称空间中定义消息,并且两个返回类型都包含元素ReturnValue,所以在urn:ReturnValue元素定义两次时会出现冲突,一次为一个int和一个字符串。

要演示请参阅以下内容,GetIntData操作注释掉,请参阅定义的ReturnValue元素:

<!-- from the XSD http://localhost/Service1.svc?xsd=xsd0 -->
<xs:element name="SingleTypeResponseOf_String">
  <xs:complexType>
    <xs:sequence>
      <xs:element minOccurs="0" ref="q1:ReturnValue" 
                  xmlns:q1="http://tempuri.org/" /> 
    </xs:sequence>
  </xs:complexType>
</xs:element>

<!-- from the XSD http://localhost/Service1.svc?xsd=xsd2 -->
<xs:schema elementFormDefault="qualified" 
           targetNamespace="http://tempuri.org/" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           xmlns:tns="http://tempuri.org/">
  <xs:element name="ReturnValue" 
              nillable="true" 
              type="xs:string" /> 
</xs:schema>

如何允许MessageContract重命名ReturnValue属性?我不认为你可以使用DataContractSerializer。

解决方案是什么?好吧,我认为没有使用[MessageBodyMember]的解决方案。如果您使用[DataMember],它将正常工作。你之前提到过你正在使用net.tcp,所以我假设你的.NET为.NET。您是否需要对SOAP信封进行这种级别的控制?

通常情况下,我尽可能使用DataContract,并且只在必要时冒险进入MessageContract - 与旧的SOAP风格平台接口。