Wcf 共享数据协定的子类型

Wcf 共享数据协定的子类型,wcf,Wcf,根据互联网上人们关于服务引用的建议,我现在将其删除,并将服务/数据契约拆分为服务器和客户端都可以访问的公共程序集。总的来说,这似乎非常有效 但是,当我尝试在服务中使用自定义对象,或者更确切地说是自定义子类型时,会遇到问题。最初,我只想将公共程序集中的接口定义为数据的契约。我很快就明白了这是行不通的,因为当从服务接收对象时,客户端需要一个具体的类来实例化对象。所以我用了一个简单的类,基本上是这样的: // (defined in the common assembly) public class

根据互联网上人们关于服务引用的建议,我现在将其删除,并将服务/数据契约拆分为服务器和客户端都可以访问的公共程序集。总的来说,这似乎非常有效

但是,当我尝试在服务中使用自定义对象,或者更确切地说是自定义子类型时,会遇到问题。最初,我只想将公共程序集中的接口定义为数据的契约。我很快就明白了这是行不通的,因为当从服务接收对象时,客户端需要一个具体的类来实例化对象。所以我用了一个简单的类,基本上是这样的:

// (defined in the common assembly)
public class TestObject
{
    public string Value { get; set; }
}
// (defined on the server)
public class DbTestObject : TestObject
{
    public string Value { get; set; }
    public DbTestObject(string val)
    {
        Value = val;
    }
}
然后在服务契约(接口)中,我有一个方法返回这样一个对象

现在,如果我只是在服务实现中创建这样一个对象并返回它,它就可以正常工作了。但是,我想在服务(或底层业务逻辑)中定义it的一个子类型,它定义了更多的东西(例如,用于数据库访问的方法,或仅用于对象的一些方法)

为了简单起见,子类型如下所示:

// (defined in the common assembly)
public class TestObject
{
    public string Value { get; set; }
}
// (defined on the server)
public class DbTestObject : TestObject
{
    public string Value { get; set; }
    public DbTestObject(string val)
    {
        Value = val;
    }
}
在服务中,我没有创建
TestObject
,而是创建子类型并返回它:

public TestObject GetTestObject()
{
    return new DbTestObject("foobar");
}
如果我现在运行它,并让客户端调用
GetTestObject
,那么我会立即得到一个带有以下错误文本的
CommunicationException
:套接字连接被中止。这可能是由于处理消息时出错、远程主机超过接收超时或基础网络资源问题造成的。本地套接字超时为“00:09:59.9380000”

我已经发现,这是因为客户端不知道如何反序列化
DbTestObject
。一个解决方案是使用
KnownTypeAttribute
声明基类型,以使其了解子类型。但这需要将子类型移动到公共程序集中,这当然是正确的我想避免的方法,因为我希望逻辑与客户机分离


有没有一种方法可以告诉客户端只使用
TestObject
类型进行反序列化;或者这种方法的解决方案是使用数据传输对象?

正如@Sixto Saez所指出的那样,继承和WCF往往不能很好地结合在一起。原因是继承在很大程度上属于OO世界,而不是mes掠过世界

话虽如此,如果您控制着服务的两端,KnownType允许您摆脱消息传递的限制,并利用继承的好处。为了避免依赖关系,您可以利用KnownTypeAttribute的功能获取方法名,而不是类型参数。这允许您动态地指定运行时的已知类型

例如

[KnownType(“GetKnownTestObjects”)]
[数据合同]
公共类测试对象
{
[数据成员]
公共字符串值{get;set;}
公共静态IEnumerable GetKnownTestObjects()
{
返回Registry.GetKnown();
}
}
使用此技术,可以有效地反转依赖关系

Registry是一个简单的类,允许其他程序集在运行时将类型注册为指定基类的子类型。此任务可以在应用程序自身启动时执行,如果您愿意,也可以执行,例如,通过在包含子类型的程序集中的类型之间进行反射

这实现了允许正确处理子类型的目标,而无需TestObject程序集引用子类型程序集


我已经在“闭环”应用程序中成功地使用了此技术,在“闭环”应用程序中,客户端和服务器都受到控制。您应该注意,此技术有点慢,因为在序列化/反序列化时,必须在两端重复调用GetKnownTestObjects方法。但是,如果您准备接受此slig缺点:这是一种使用WCF提供通用web服务的相当干净的方法。它还消除了所有那些指定实际类型的“KnownTypeAttribute”的需要。

在使用基于消息的WCF框架时,只要尝试应用继承等OO概念,您就会逆流而上。在当使用WCF服务传输数据时,它们更符合消息传递的隐喻。@SixtoSaez我也这么认为,但如果您以前没有使用过它,就很难正确地使用它…:/不确定如何向自定义序列化程序描述继承链(可能通过属性)但这应该是可能的。再说一次,你是在强迫继承到消息交换模式上,但如果意愿很强烈……)哈哈,我认为意愿不够强烈。这种需要的努力通常是一种迹象,表明我的方式一点也不普通,我应该寻找其他方式:D这很酷,谢谢你。不过,这很简单这并不能真正解决我的问题,因为它仍然需要客户端知道服务器的子类型(即客户端需要在注册表中注册服务器的类型)。无论如何,我都会接受这个答案,因为它肯定会有帮助,而且我也不希望我的问题有更好的解决方案。我想从长远来看,最好是定义通用DTO。是的,它确实要求客户端知道子类型-服务器和客户端都必须以某种方式在每一端填充自己的注册表。DTO可能是一个很好的选择。另一种可能是采用组合解决方案(而不是继承解决方案)。如果服务器类型没有需要返回到客户端的额外数据,那么这种方法可能会起作用。