我需要有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”。
有人对如何解决这最后一步有任何建议吗?
我可以提供完整的资源以便更好地理解,但我不知道我是否可以在这里附上它们......
提前致谢。
答案 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感谢您的尝试。