【问题标题】:Using Interfaces With WCF将接口与 WCF 一起使用
【发布时间】:2022-02-26 17:02:34
【问题描述】:

我已经用谷歌搜索和阅读了几个小时,但找不到任何处理我的特定场景的人......

我想在我的 WCF 服务合同中使用接口,将服务与线路两端使用的类松散耦合。这将使我们能够拥有一个仅包含服务和数据合同(只是接口)的低级程序集,我们可以将其交给顾问。在他们的终端上,他们可以实例化实现我们的 Data Contract 接口的数据类,通过网络将其发送给我们,然后我们的 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 序列化为&lt;IDataContract&gt;&lt;MyProperty&gt;client data&lt;/MyProperty&gt;&lt;/IDataContract&gt;,然后能够将其反序列化为ServerDataClass 实例。这似乎应该是可能的。

【问题讨论】:

  • 我应该注意,我已经阅读了很多关于 ServiceKnownTypeAttribute 的内容,但这不符合这里的要求。我需要具有服务接口的程序集对实现该接口的类一无所知。我不知道我上面的问题是否说明了这一点。
  • 为什么要为相同的合同使用不同的名称?合同就是合同……
  • 名字不是重点,两个不同的具体实现才是关键。来回传递的数据只是一个属性包。如果它们都实现相同的接口,为什么不能在电线的一端成为 Class1,然后在电线的另一端成为 Class2?
  • 我已经澄清了代码并包含了更多内容。希望这会减轻 Gerrie 所经历的困惑。
  • 然而,在我的搜索中,我发现了许多其他解释略有不同的情况的实例,人们说这是不可能的。但是我找不到任何人解决了我的具体情况并说你不能这样做。那么您对我的问题有任何实际反馈吗?或者你只是认为批评我的实际要求就足够了?

标签: c# .net wcf known-types


【解决方案1】:

如果您的数据协定是接口,WCF 无法知道要为传入请求实例化什么对象。类不需要和服务中的一样,毕竟 Add Service Reference 会读取 WSDL 并根据 WSDL 中的类型信息生成新的类。

【讨论】:

  • 如何告诉 WCF what 类在不使用特定类名定义服务接口的情况下专门实例化? App.config 很好,我的实际 .svc 文件中的属性......随便。只要定义了服务接口的程序集就不必这样做。
  • 我应该提到您的回复至少帮助我使抽象基类正常工作。我查看了 Add Service Reference 生成的内容,并使用了其中的一些内容。所以谢谢。
【解决方案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;
          }
        }
      }
    }
  }
}

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2017-04-16
      • 2012-02-23
      • 2019-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-08
      • 2011-02-04
      相关资源
      最近更新 更多