使用与WCF的接口

时间:2010-11-16 07:40:11

标签: c# .net wcf known-types

我已经Google搜索并阅读了几个小时,我找不到任何处理我特定情况的人......

我想在我的WCF服务合同中使用接口,以便从线路每端使用的类中松散地耦合服务。这将使我们能够拥有一个低级程序集,其中只包含我们可以提供给顾问的服务和数据合同(只是接口)。在他们的结束时,他们可以实例化他们实现我们的数据合同接口的数据类,通过网络将它发送给我们,然后我们的WCF服务将转换/转换/输入任何数据到我们的实现相同接口的数据类的版本。

这是一个例子。 IDataContract包含我想通过网络传输的裸信息。端点和其他特定于WCF的配置都是默认的东西(我的问题可能在于,所以如果我需要更改内容,我可以包含更多内容)。

编辑:我已经包含了更多代码,并重命名了几个类来帮助它减少混乱。名字和名称DataContractAttributes的命名空间添加以及配置文件中的两个部分是基于来自this blog post的信息的新增内容。如果我切换到抽象基类而不是接口,它可以工作。但是,如果可能的话,我想使用界面。

共享库(我的代码,与客户作者共享):

public interface IDataContract
{
    string MyProperty { get; set; }
}
[ServiceContract]
public interface ITestService
{
    [OperationContract]
    IDataContract TestSharedInterface(IDataContract clientData);
}

客户代码(他们的):

[DataContract(Name = "IDataContract", Namespace = "http://services.sliderhouserules.com")]
public class ClientDataClass : IDataContract
{
    [DataMember]
    public string MyProperty { get; set; }
}
private static void CallTestSharedInterface()
{
    EndpointAddress address = new EndpointAddress("http://localhost/ServiceContractsTest.WcfService/TestService.svc");
    ChannelFactory<ITestService> factory = new ChannelFactory<ITestService>("ITestService", address);
    ITestService proxy = factory.CreateChannel();
    ((IClientChannel)proxy).Open();

    IDataContract clientData = new ClientDataClass() { MyProperty = "client data" };
    IDataContract serverData = proxy.TestSharedInterface(clientData);
    MessageBox.Show(serverData.MyProperty);
}

客户端配置:

<system.runtime.serialization>
    <dataContractSerializer>
        <declaredTypes>
            <add type="ServiceContractsTest.Contracts.DataContracts.IDataContract, ServiceContractsTest.Contracts">
                <knownType type="ServiceContractsTest.WcfClient.ClientDataClass, ServiceContractsTest.WcfClient"/>
            </add>
        </declaredTypes>
    </dataContractSerializer>
</system.runtime.serialization>

服务器代码(我的):

public class TestService : ITestService
{
    public IDataContract TestSharedInterface(IDataContract clientData)
    {
        ServerDataClass convertedClientData = (ServerDataClass)clientData;
        IDataContract serverData = new ServerDataClass() { MyProperty = convertedClientData.MyProperty + " + server data added" };
        return serverData;
    }
}
[DataContract(Name = "IDataContract", Namespace = "http://services.sliderhouserules.com")]
public class ServerDataClass : IDataContract
{
    [DataMember]
    public string MyProperty { get; set; }
}

服务器配置:

<system.runtime.serialization>
    <dataContractSerializer>
        <declaredTypes>
            <add type="ServiceContractsTest.Contracts.DataContracts.IDataContract, ServiceContractsTest.Contracts">
                <knownType type="ServiceContractsTest.WcfService.ServerDataClass, ServiceContractsTest.WcfService"/>
            </add>
        </declaredTypes>
    </dataContractSerializer>
</system.runtime.serialization>

我在客户端调用上收到序列化错误抱怨已知类型。我刚刚在该客户端类中缺少一些元数据标记吗?我甚至不知道在哪里知道这个问题甚至是谎言,因为我已经尝试了所有我能想到的搜索,似乎没有人能够处理这个具体的情况。

基本上,我希望ClientDataClass序列化为<IDataContract><MyProperty>client data</MyProperty></IDataContract>,然后能够将其反序列化为ServerDataClass实例。这似乎应该是可能的。

3 个答案:

答案 0 :(得分:3)

如果您的数据合同是接口,则WCF无法知道要为传入请求实例化的对象。在所有Add Service Reference读取WSDL并根据WSDL中的类型信息生成新类之后,不需要该类与服务中的类相同。

答案 1 :(得分:2)

此博客为我提供了找到问题解决方案的正确方向。实际上我的帖子与 sliderhouserules 描述完全相同。

但在我的场景中,我不能使用任何抽象或基类来继承。所以我使用了TypesHelper类来自己读取dataContractSerializer部分,并将相关类型传递给WCF服务。

namespace ExampleNamespace
{
  public interface IJustAInstance { }

  [ServiceContract]
  [ServiceKnownType("GetKnownTypes", typeof(ExampleNamespace.TypesHelper))]
  public interface ICreateInstance
  {
    IJustAInstance CreateInstance();
  }

  public static class TypesHelper
  {
    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
    {
      DataContractSerializerSection section = (DataContractSerializerSection)
        ConfigurationManager.GetSection(
        "system.runtime.serialization/dataContractSerializer");
      if (dataContractSerializerSection != null)
      {
        foreach (DeclaredTypeElement item in dataContractSerializerSection.DeclaredTypes)
        {
          foreach (TypeElement innterItem in item.KnownTypes)
          {
            Type type = Type.GetType(innterItem.Type);
            if (typeof(IJustAInstance).IsAssignableFrom(type ))
              yield return type;
          }
        }
      }
    }
  }
}

答案 2 :(得分:0)

您可以创建ClientContract和ServerContract可以提供的BaseContract(作为属性),并且可以在创建ClientContract或ServerContract的新实例时在相应的构造函数中使用。 然后,您只需将BaseContract添加到共享库中。