WCF:介面、泛型和 ServiceKnownType
我有以下內容:
[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 < SportProgram >)) …
請注意,這是生成的參考存根,看起來像這樣,所以我可以看到已知類型被正確地引入:
[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; } }乾杯安東尼
好吧,我認為這是 SOA 與 OOP“阻抗不匹配”的另一種情況。兩個世界是完全不同的。
在 WCF 中,從客戶端傳遞到伺服器的所有內容都作為序列化消息傳遞- 不使用任何引用。
這意味著:您想要在客戶端序列化、將其發送到伺服器、反序列化並在那裡使用它的所有內容,都必須是具體的——你不能傳遞介面,你不能使用“未解析”的泛型——你需要拼出來。基本上,從客戶端通過線路傳遞到伺服器的所有內容都必須在 XML 模式中表示。
這有很多含義:
- 沒有介面 - 你不能傳遞介面 - 你需要使用具體類型
- 沒有“自動”繼承——你不能只定義一個基類並基於它傳遞派生類——這些也需要指定(這就是 ServiceKnownType 屬性的用途)
- 沒有自動泛型 - 再次,您需要使用具體類型
這聽起來可能有很多限制——但這是因為 WCF 使用所有基於消息的通信——它無法處理引用、繼承、泛型等——你需要把它拼出來。
所以我本身並沒有真正的答案 - 我只是認為你需要重新考慮你的策略並改變你的客戶端和伺服器通過 WCF 交換資訊的方式。
馬克
PS:我做了更多的研究,與我的理解相反,似乎有一種方法可以序列化任何基於介面和/或抽象基類的東西,只要你能確定它總是只有 . NET 網路的兩端(即它不能與 Java 等互操作)。
請參閱NetDataContractSerializer 上的 Aaron Skonnard 部落格文章和另一篇部落格文章,以及另一篇展示如何使用 NetDataContractSerializer 能夠將諸如
IPerson參數之類的東西傳遞給方法的文章。