我正在尝试实现一个服务契约,其中包含一个采用通用接口的方法,并且该泛型接口本身具有一个接口参数.我用ServiceKnownType修饰了服务接口,我用常规的KnownType修改了服务实现,并且我用常规的KnownType修饰了datacontract实现:
[ServiceContract(SessionMode = SessionMode.required,CallbackContract = typeof(ICallbacks))] [ServiceKnownType(typeof(Batch<object>))] [ServiceKnownType(typeof(Command))] public interface IActions { [OperationContract] IResponse TakeAction(IBatch<ICommand> commands); } [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,ConcurrencyMode = ConcurrencyMode.Reentrant)] [KnownType(typeof(Batch<object>))] [KnownType(typeof(Command))] internal class Actions : IActions { } [DataContract] [KnownType(typeof(Command))] public class Batch<T> : IBatch<T> { }
为了记录,我在那里有Batch,因为看起来你只能表示一次泛型类型的知识类型 – 它似乎发出BatchOfanyType,但我不知道如何处理它.
我得到的例外是“将任何静态未知的类型添加到已知类型列表中 – 例如,通过使用KnownTypeAttribute属性或将它们添加到传递给DataContractSerializer的已知类型列表中.”
有什么明显的我做错了吗?是否不支持接口的通用接口?为了记录我在这个项目的C#2.0和.NET 3.0上.
解决方法
如果你真的想要,你可以在服务合同定义中使用接口,只要你包括你正在做的已知类型(稍作调整,见下文).
显然,使用接口作为泛型类型参数使其成为C#3.0的桥梁.我将已知的type属性更改为
[ServiceKnownType(typeof(Batch<Command>))] public interface IActions { }
这使得它在某种程度上起作用.序列化和反序列化本身也可以,但是你遇到了这个例外:
Unable to cast object of type ‘Batch`1[Command]’
to type ‘IBatch`1[ICommand]’.
要使该转换工作,您需要语言支持泛型类型协方差,这是C#4.0中引入的.但是要在C#4.0中工作,你需要添加一个方差修饰符:
public interface IBatch<out T> { }
然后它完美地工作…不幸的是你没有使用C#4.0.
关于在服务合同中使用接口的最后一件事:如果您从它们生成服务引用,它将所有接口参数键入为对象,因为原始接口类型不是元数据的一部分.您可以通过程序集引用共享契约,或手动重构生成的代理来修复它,但总而言之,使用与WCF的接口可能比它的价值更麻烦.