WCF:元素已导出错误

Cra*_* W. 5 wcf

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

我们的消息合同定义如下.

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

服务接口具有以下内容:

[OperationContract]
SingleTypeResponse<string> GetStringData();

[OperationContract]
SingleTypeResponse<int> GetIntData();
Run Code Online (Sandbox Code Playgroud)

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

调用WSDL导出扩展时抛出异常:System.ServiceModel.Description.DataContractSerializerOperationBehavior contract:http://tempuri.org/:IService1 ----> System.InvalidOperationException:WcfService1.IService1.GetIntData操作引用a已从WcfService1.IService1.GetStringData操作导出的message元素[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>
Run Code Online (Sandbox Code Playgroud)

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

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

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

我收到相同的错误消息,但它所抱怨的消息元素是合同的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>
Run Code Online (Sandbox Code Playgroud)

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

Kir*_*rst 3

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

这里有一些潜在的冲突。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>
Run Code Online (Sandbox Code Playgroud)

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

我相信你的第二个冲突来自属性MessageBodyMember。因为这两个操作都在同一命名空间中定义消息,并且两个返回类型都包含一个 element ReturnValue,所以您会遇到冲突,该urn:ReturnValue元素被定义两次,一次作为 int ,一次作为 string 。

为了演示,请参阅以下内容,将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>
Run Code Online (Sandbox Code Playgroud)

你怎么能允许他们MessageContract重命名ReturnValue财产呢?我认为 DataContractSerializer 不能。

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

通常我会DataContract尽可能多地使用,并且只MessageContract在必要时才冒险使用 - 与旧的 SOAP 风格平台交互。