WCF具有重复方法名称的多个合同

时间:2010-03-09 17:47:06

标签: c# wcf

我有多个合同的服务。

[ServiceContract]
public partial interface IBusinessFunctionDAO {

    [OperationContract]
    BusinessFunction GetBusinessFunction(Int32 businessFunctionRefID);

    [OperationContract]
    IEnumerable<Project> GetProjects(Int32 businessFunctionRefID);
}

[ServiceContract]
public partial interface IBusinessUnitDAO {

    [OperationContract]
    BusinessUnit GetBusinessUnit(Int32 businessUnitRefID);

    [OperationContract]
    IEnumerable<Project> GetProjects(Int32 businessUnitRefID);
}

然后我明确地实现了每个接口,如此。

public class TrackingTool : IBusinessFunctionDAO, IBusinessUnitDAO {

    BusinessFunction IBusinessFunctionDAO.GetBusinessFunction(Int32 businessFunctionRefID) {
      // implementation
    }
    IEnumerable<Project> IBusinessFunctionDAO.GetProjects(Int32 businessFunctionRefID) {
      // implementation
    }

    BusinessUnit IBusinessUnitDAO.GetBusinessUnit(Int32 businessUnitRefID) {
      // implementation
    }
    IEnumerable<Project> IBusinessUnitDAO.GetProjects(Int32 businessUnitRefID) {
      // implementation
    }
}

正如您所看到的,我有两个GetProjects(int)方法,但每个方法都是显式实现的,因此编译得很好并且完全有效。当我真正将其作为一项服务开始时,问题就出现了。它给我一个错误,因为TrackingTool已经包含一个定义GetProject。虽然这是真的,但它是不同服务合同的一部分。在生成方法名称时,WCF是否无法区分服务合同? 有没有办法让它区分服务合同?

我的App.Config看起来像这样

<service name="TrackingTool">
  <endpoint address="BusinessUnit" contract="IBusinessUnitDAO" />
  <endpoint address="BusinessFunction" contract="IBusinessFunctionDAO" />
</service>

任何帮助都将不胜感激。

谢谢,劳尔

3 个答案:

答案 0 :(得分:10)

我想我找到了它的原因。在WSDL中,函数公开如下:

<wsdl:message name="IBusinessUnitDAO_GetBusinessUnitProjects_InputMessage">
  <wsdl:part name="parameters" element="tns:GetBusinessUnitProjects" />
</wsdl:message>
<wsdl:message name="IBusinessFunctionDAO_GetBusinessFunctionProjects_InputMessage">
  <wsdl:part name="parameters" element="tns:GetBusinessFunctionProjects" />
</wsdl:message>

然后在定义tns:namespace的xsd中我们有以下内容:

<xs:element name="GetBusinessUnitProjects">
  <xs:complexType>
    <xs:sequence>
      <xs:element minOccurs="0" name="businessUnitRefID" type="xs:int" />
    </xs:sequence>
  </xs:complexType>
</xs:element>

<xs:element name="GetBusinessFunctionProjects">
  <xs:complexType>
    <xs:sequence>
      <xs:element minOccurs="0" name="businessFunctionRefID" type="xs:int" />
    </xs:sequence>
  </xs:complexType>
</xs:element>

因此即使服务暴露两个不同的契约,冲突的原因也是因为所有wsdl部分元素都在同一个命名空间中。因此,当您创建两个相同的函数名时,您将获得具有相同名称的重复元素,从而导致问题。因此,问题的解决方案是为每个服务契约添加名称空间属性。如果我们采取原始服务合同并按此修改。

[ServiceContract(Namespace="Tracking/BusinessFunction")]
public partial interface IBusinessFunctionDAO {

    [OperationContract]
    BusinessFunction GetBusinessFunction(Int32 businessFunctionRefID);

    [OperationContract]
    IEnumerable<Project> GetProjects(Int32 businessFunctionRefID);
}

[ServiceContract(Namespace="Tracking/BusinessUnit")]
public partial interface IBusinessUnitDAO {

    [OperationContract]
    BusinessUnit GetBusinessUnit(Int32 businessUnitRefID);

    [OperationContract]
    IEnumerable<Project> GetProjects(Int32 businessUnitRefID);
}

当我们生成WSDL时,我们为每个创建的命名空间获取一个WSDL。此命名空间的每个端口都标识有其所有操作和元素。因此,在我们的每个单独的WSDL中,我们得到以下结果:

//File: Tracking.BusinessFunction.wsdl
<wsdl:message name="IBusinessFunctionDAO_GetProjects_InputMessage">
  <wsdl:part name="parameters" element="tns:GetProjects" />
</wsdl:message>

//File: Tracking.BusinessUnit.wsdl
<wsdl:message name="IBusinessUnitDAO_GetProjects_InputMessage">
  <wsdl:part name="parameters" element="tns:GetProjects" />
</wsdl:message>

正如您所看到的,它们都具有相同的元素名称,但由于它们位于不同的名称空间中,因此元素不再相互冲突。如果我们看一下xsd,它们现在已经定义了相同的元素,但具有不同的参数:

//File: Tracking.BusinessFunction.xsd
<xs:element name="GetProjects">
  <xs:complexType>
    <xs:sequence>
      <xs:element minOccurs="0" name="businessFunctionRefID" type="xs:int" />
    </xs:sequence>
  </xs:complexType>
</xs:element>

//File: Tracking.BusinessUnit.xsd
<xs:element name="GetProjects">
  <xs:complexType>
    <xs:sequence>
      <xs:element minOccurs="0" name="businessUnitRefID" type="xs:int" />
    </xs:sequence>
  </xs:complexType>
</xs:element>

所以我原来问题的答案是让每个服务合同都在一个单独的命名空间中,这样你就不会有冲突的端口元素。这也使您可以灵活地将合同放在单独的WSDL中,如果您要分发它们中的一部分,则更容易管理。

答案 1 :(得分:4)

您可以尝试使用别名:

[OperationContract(Name = "YourMethodNameHere")]
IEnumerable GetProjects(Int32 businessUnitRefID);

请参阅:http://jeffbarnes.net/blog/post/2006/09/21/Overloading-Methods-in-WCF.aspx

答案 2 :(得分:0)

尝试在OperationContract属性上为具有相同名称的两个方法设置Action属性以消除冲突,如下所示:

[ServiceContract]
public partial interface IBusinessFunctionDAO {

[OperationContract]
BusinessFunction GetBusinessFunction(Int32 businessFunctionRefID);

[OperationContract(Action="GetBusinessFunctionProjects")]
IEnumerable<Project> GetProjects(Int32 businessFunctionRefID);
}

[ServiceContract]
public partial interface IBusinessUnitDAO {

[OperationContract]
BusinessUnit GetBusinessUnit(Int32 businessUnitRefID);

[OperationContract(Action="GetBusinessUnitProjects")]
IEnumerable<Project> GetProjects(Int32 businessUnitRefID);
}