我有以下内容:
[ServiceContract]
[ServiceKnownType(typeof(ActionParameters))]
[ServiceKnownType(typeof(SportProgram))]
[ServiceKnownType(typeof(ActionResult<SportProgram>))]
public interface ISportProgramBl
{
[OperationContract]
IActionResult<ISportProgram> Get(IActionParameters parameters);
}
当我运行Get方法时,我收到以下错误:
尝试序列化参数http://tempuri.org/:GetResult时出错。 InnerException消息是'Type'PPS.Core.DomainModel.Support.Action.ActionResult`1 [[PPS.Core.DomainModel.SportProgram.ISportProgram,PPS.Core.DomainModel,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]]'与数据契约名称'ActionResultOfanyType:http://schemas.datacontract.org/2004/07/PPS.Core.DomainModel.Support.Action'不是预期的。将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用KnownTypeAttribute属性或将它们添加到传递给DataContractSerializer的已知类型列表中。有关详细信息,请参阅InnerException。
从这个错误中我可以看到它可以解析ActionResult但是它无法解析ISportProgram,即使我的服务接口上有 ServiceKnownType(typeof(ActionResult&lt; SportProgram&gt;))。
请注意,这是生成的引用存根,如下所示,因此我可以看到已正确引入已知类型:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="SportProgramStb.ISportProgramBl")]
public interface ISportProgramBl {
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ISportProgramBl/Get", ReplyAction="http://tempuri.org/ISportProgramBl/GetResponse")]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(PPS.Core.DomainModel.SportProgram.SportProgram))]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(PPS.Core.DomainModel.Support.Action.ActionParameters))]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(PPS.Core.DomainModel.Support.Action.ActionResult<PPS.Core.DomainModel.SportProgram.SportProgram>))]
object Get(object parameters);
}
为什么会出错????请注意它正确地通过WCF服务...但它会在返回结果时抛出异常。
最后,ActionResult看起来像这样:
public interface IActionResult<T>
{
T Result { get; set; }
}
干杯 安东尼
答案 0 :(得分:15)
嗯,我认为这是SOA与OOP“阻抗不匹配”的另一个案例。这两个世界是完全分开的。
在WCF中,从客户端传递到服务器的所有内容都作为序列化消息传递 - 没有使用任何引用。
这意味着:您要在客户端上序列化的所有内容,将其发送到服务器,然后反序列化并在那里使用它,必须具体 - 您无法传递接口,您无法使用“未解决的”泛型 - 你需要拼写出来。基本上,所有通过网络从客户端传递到服务器的都必须在XML模式中表达。
这有很多含义:
这可能听起来有很多限制 - 但这是因为WCF正在使用所有基于消息的通信 - 它无法处理引用,继承,泛型等 - 你需要拼写出来。
所以我本身并没有给你答案 - 我只是认为你需要重新思考你的策略并改变客户端和服务器通过WCF交换信息的方式。
马克
PS:我做了更多的研究,与我的理解相反,似乎有一种方法可以序列化基于接口和/或抽象基类的任何东西,只要你能确定它是在线路的任何一端始终只有.NET(即不可与Java进行互操作)。请参阅Aaron Skonnard blog post on the NetDataContractSerializer和另一个blog post和yet another,了解如何使用NetDataContractSerializer将IPerson
之类的内容作为参数传递给您的方法。
答案 1 :(得分:2)
这是我用ServiceStack.NET - 我的开源.NET和MONO Web服务框架解决的问题之一。
服务堆栈受Martin Fowlers Data Transfer Object Pattern的影响很大,因为它允许您简单地使用DTO来定义您的Web服务 - 即SOA方式:)。
我通过生成我自己的WSDL来避免这种在WCF中固有的限制,其行为与您期望的一样。作为替换WCF的复杂配置/ ServiceContract模型的好处 - SOAP Web服务也适用于MONO - see the live demo。
答案 2 :(得分:1)
这是一个古老的问题,尽管接受的答案是完全正确的,但我在寻找类似问题的过程中不知所措,并认为我可以分享我的经验。它经常令人头痛,但可以将泛型与WCF接口结合使用。这是我已经完成的另一个(类似的)实现的工作示例:
[ServiceContract]
[ServiceKnownType(typeof(CollectionWrapper<IAssociation>))]
public interface IService :
{
[OperationContract]
ICollectionWrapper<IAssociation> FindAssociation(string name, int pageSize, int page);
}
public interface ICollectionWrapper<TModel>
{
int TotalCount { get; set; }
IEnumerable<TModel> Items { get; set; }
}
[KnownType(typeof(OrganizationDto))]
[KnownType(typeof(CompanyDto))]
public class CollectionWrapper<TModel> : ICollectionWrapper<TModel>
{
[DataMember]
public int TotalCount { get; set; }
[DataMember]
public IEnumerable<TModel> Items { get; set; }
}
public class CompanyDto : IAssociation
{
public int Id { get; set; }
public string Name { get; set; }
}
public class OrganizationDto : IAssociation
{
public int Id { get; set; }
public string Name { get; set; }
}
此处的关键是使用KnownType
和ServiceKnownType
的组合。
所以在你的情况下你可以这样做:
[ServiceContract]
[ServiceKnownType(typeof(ActionParameters))]
[ServiceKnownType(typeof(ActionResult<ISportProgram>))] // Actual implementation of container, but interface of generic.
public interface ISportProgramBl
{
[OperationContract]
IActionResult<ISportProgram> Get(IActionParameters parameters);
}
[KnownType(typeof(SportProgram))] // Actual implementation here.
public class ActionResult<T>
{
// Other stuff here
T FooModel { get; set; }
}
如果您有共享合同(访问实际服务接口)并使用ChannelFactory<ISportProgramBl>
合同,这将有效。我不知道它是否适用于服务引用。
然而,这里提到的实施似乎存在一些问题:
WCF With a interface and a generic model
另一个类似的问题在这里提出并回答:
答案 3 :(得分:0)
您是在对象中指定接口而不是具体类型吗?
PPS.Core.DomainModel.Support.Action.ActionListResult<IList<PPS.Core.DomainModel.SportProgram.ISportProgram>>
编辑:
我所说的是,您在通用类型列表中传递的泛型(包括通过接口的子对象)中传递的所有具体类型。我们遇到了所有类型都不知道的问题。
答案 4 :(得分:0)
您正在返回T的IList。可能系统在查找T是什么时遇到问题。
不确定是否可以返回接口而不是类型。