WCF:通用接口的序列化是否可行?

我正在尝试实现一个服务契约,其中包含一个采用通用接口的方法,并且该generics接口本身具有一个接口参数。 我用ServiceKnownType修饰了服务接口,我用常规的KnownType修改了服务实现,并且我用常规的KnownType修饰了datacontract实现:

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ICallbacks))] [ServiceKnownType(typeof(Batch))] [ServiceKnownType(typeof(Command))] public interface IActions { [OperationContract] IResponse TakeAction(IBatch commands); } [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)] [KnownType(typeof(Batch))] [KnownType(typeof(Command))] internal class Actions : IActions { } [DataContract] [KnownType(typeof(Command))] public class Batch : IBatch { } 

为了记录,我在那里有批处理,因为看起来你只能表达一个generics类型的知识类型 – 它似乎发出BatchOfanyType,但我不知道如何处理它。

我得到的例外是“将任何静态未知的类型添加到已知类型列表中 – 例如,通过使用KnownTypeAttribute属性或将它们添加到传递给DataContractSerializer的已知类型列表中。”

有什么明显的我做错了吗? 是否不支持接口的通用接口? 为了记录我在这个项目的C#2.0和.NET 3.0上。

如果你真的想要,你可以在服务合同定义中使用接口,只要你包括你正在做的已知类型(稍作调整,见下文)。

显然,使用接口作为generics类型参数使其成为C#3.0的桥梁。 我将已知的type属性更改为

 [ServiceKnownType(typeof(Batch))] public interface IActions { } 

这使得它在某种程度上起作用。 序列化和反序列化本身也可以,但是你遇到了这个例外:

无法将’Batch`1 [Command]’类型的对象强制转换为’IBatch`1 [ICommand]’。

要使该转换工作,您需要语言支持generics类型协方差,这是C#4.0中引入的。 但是要在C#4.0中工作,你需要添加一个方差修饰符:

 public interface IBatch { } 

然后它完美地工作…不幸的是你没有使用C#4.0。

关于在服务合同中使用接口的最后一件事:如果您从它们生成服务引用,它将所有接口参数键入为object ,因为原始接口类型不是元数据的一部分。 您可以通过程序集引用共享契约,或手动重构生成的代理来修复它,但总而言之,使用与WCF的接口可能比它的价值更麻烦。

WCF是一个基于SOA消息的系统 – 它可以以XML格式表示的序列化XML格式通过线路发送任何内容。

遗憾的是,XML模式既不知道接口也不知道任何东西,所以不 – 你不能一般地序列化那些 – 你需要使用具体的类型。

您无法序列化界面。 接口只定义契约,而不是对象。 我猜这个例外是ISerializable接口。

generics可以序列化,但有一定的局限性。 例如,给定数据合同:

 [DataContract] public class Foo { [DataMember] public T Value { get; set; } } 

和服务合同:

 [ServiceContract] public interface IService1 { [OperationContract] Foo GetData(); } 

并且服务实现:

 public class Service1 : IService1 { public Foo GetData() { return new Foo() { Value = "My test string" }; } } 

在为上述服务设置服务引用后,可以运行以下代码:

 ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(); ServiceReference1.FooOfstring temp = client.GetData(); MessageBox.Show(temp.Value); 

并显示带有“我的测试字符串”的消息框。

请注意,服务本身不是通用的,但使用的数据合同是。 此外,在客户端生成的数据协定不是通用的,而是具有类型为string的属性值的“扁平”类:

 [System.Runtime.Serialization.DataMemberAttribute()] public string Value { get {...} set {...} }