WCF和接口

时间:2011-03-28 09:34:14

标签: wcf

我需要有2个类的系列(一个在服务器上,一个在客户端),它们的数据结构相同但行为不同。另外我认为这些fmailies足够大,因此我不想实现DTO的中间级别和转换。 我决定采用以下方式:声明共享程序集,声明数据和服务接口,如下所示:

public interface ITest
{
    string Title { get; set; }
    int Value { get; set; }
}
public interface IService
{
    ITest GetData();
}

有了这些声明,我可以在服务器端实现这些接口,例如基于实体框架(数据)和WCF(服务)。在客户端,我可以使用例如依赖属性(数据)和WCF(服务)。 当我开始尝试实现这一点时,我遇到了几个问题。 第一个是关于WCF的服务器端 - 它根本不想使用接口作为返回参数。感谢StackOverflow,此问题已解决,如here
接下来的问题是服务器端呈现的XML包括服务器类上序列化的qulified程序集名称。

      <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">  
        <s:Body>
          <GetDataResponse xmlns="http://tempuri.org/">
            <Test z:Id="1" z:Type="Dist.Server.Model.Test" z:Assembly="Dist.Server, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns="http://schemas.datacontract.org/2004/07/Dist.Server.Model" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
              <Title z:Id="2">Test</Title>
              <Value>123</Value>
            </Test>
          </GetDataResponse>
        </s:Body>
      </s:Envelope>

因此,在客户端反序列化期间,尝试加载此类型。由于这种类型在客户端无法访问,我不得不实现某种类型的映射。我发现这很容易,因为用于序列化的 NetDataContractSerializer 支持 Binder 属性。因此,我在客户端覆盖此属性并返回正确的值(同时硬编码,但测试可以。)

public class NetBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName) {
        var type = Type.GetType("Client.Test, Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
        return type;
    }
}

现在我有以下图片:
- 服务器使用 NetDataContractSerializer 来序列化响应。它在序列化期间使用实际值(calss)而不是在服务声明(接口)中使用的类型 - 客户端接收XML并开始反序列化。要解析类型, NetDataContractSerializer 会调用返回正确类型的Binder - NetDataContractSerializer 创建正确类型的实例并开始加载其属性 在这里,我遇到了麻烦,我不知道如何解决。属性值未反序列化。这意味着正确创建了类的实例(通过反射服务创建了未初始化的实例),但所有属性都是默认值(0或null)。 我尝试在客户端使用类声明:将其标记为[Serializable],实现ISerializable等,但是nohing是有帮助的。 NetDataContractSerializer 要求将类标记为[DataContract]或[Serializable]。第一个选项将属性留空,第二个选项导致异常,例如“&lt; / Test&gt;是意外的,预期是bla-bla-bla_Value_Ending_bla-bla-bla”。

有人对如何解决这最后一步有任何建议吗?

我可以提供完整的资源以便更好地理解,但我不知道我是否可以在这里附上它们......

提前致谢。

2 个答案:

答案 0 :(得分:1)

你可以看一下像AutoMapper这样的框架,它们会关注DTO的转换。这会让你的生活更轻松。

除了使用接口之外,为什么不创建一个只包含数据的基类,并通过共享包含此类的程序集在两侧继承它。使用ServiceKnownType可以帮助您解决最后的问题。

您也可以在双方共享相同的基类,并将特定逻辑实现为扩展方法。

答案 1 :(得分:0)

似乎问题很容易解决。我创建了自己的序列化程序并使用它而不是 NetDataContractSerializer 。代码很简单:

public class MySerializer: XmlObjectSerializer
{
    public override void WriteStartObject(XmlDictionaryWriter writer, object graph) {
    }

    public override void WriteObjectContent(XmlDictionaryWriter writer, object graph) {
        var formatter = new XmlSerializer(graph.GetType());
        formatter.Serialize(writer, graph);
    }

    public override void WriteEndObject(XmlDictionaryWriter writer) {
    }

    public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName) {
        var realType = Type.GetType("Client.Test, Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); //temporary solution
        var formatter = new XmlSerializer(realType);
        return formatter.Deserialize(reader);
    }

    public override bool IsStartObject(XmlDictionaryReader reader) {
        return true;//temporary solution
    }

}

我检查了从服务器到客户端的SOAP,它与 NetDataSerializer 渲染几乎相同。唯一的区别在于属性xmlns =“”。

Kai,Johann感谢您的尝试。