2011-05-24 105 views
18

我創建了一個WCF服務,並且在處理一些序列化問題時遇到了很多麻煩。也許,這只是1的方式來做到這一點,但我想確認一下 這裏是我的示例代碼:WCF,接口返回類型和KnownTypes

合同

public interface IAtm 
    { 
     [DataMember] 
     double Latitude { get; set; } 

     [DataMember] 
     double Longitude { get; set; } 
    } 

[ServiceContract] 
    public interface IAtmFinderService 
    { 

     [OperationContract] 
     ICollection<IAtm> GetAtms(); 

    } 

服務實現:

[KnownType(typeof(Atm))] 
[KnownType(typeof(List<Atm>))] 
[ServiceKnownType(typeof(Atm))] 
[ServiceKnownType(typeof(List<Atm>))] 
public class AtmFinderService : IAtmFinderService 
{ 
    public ICollection<IAtm> GetAtms() 
    { 
     return new List<IAtm>() 
      { 
       new Atm() { Latitude = 1, Longitude = 1 }, 
       new Atm() { Latitude = 2, Longitude = 2 } 
      }; 
    } 
} 

我添加了所有的KnownType和ServiceKnownType屬性,因爲我認爲那裏缺少一些東西。 所以現在,我一直在做一些測試。我試着創建一個控制檯應用程序,使用「添加服務引用」方法使VS自動創建代理。這樣一來,我得到這樣

object[] GetAtms(); 

當試圖調用它的函數,我得到這個錯誤:

設置InnerException消息是「 類型‘WCFTest.Atm’數據合同名稱 」 Atm:http://schemas.datacontract.org/2004/07/WCFTest' 不是預期的。考慮使用 DataContractResolver或不添加靜態已知的 已知類型列表中的任何類型的 - 例如,通過使用 的KnownTypeAttribute屬性或者 將其添加到傳遞給DataContractSerializer的已知類型 列表「。

非常好...那麼,我認爲VS的自動生成的代碼是廢話。我在我的服務(以及所有相關的類和實現)中做了以下更改:

[OperationContract] 
     ICollection<Atm> GetAtms(); 

所以現在,我返回一個具體類型。在更新服務引用之後,它將創建Atm類的副本及其成員和內容。 調用服務後,調用成功。 我認爲這是一些與自動生成的代碼有關的不良行爲,所以我嘗試創建一個非常簡單的主機/客戶端應用程序。我開始了一個控制檯主機監聽某個端口,然後創建了一個使用ClientBase類來調用該服務的客戶端。相同的行爲...如果服務實現返回接口類型,則失敗。如果我改變它返回具體類型,它的工作原理。我認爲我對KnownType屬性有一些問題,我必須缺少序列化程序無法處理的內容。但我不知道是什麼。

回答

36

好吧,我設法解決它 的問題,在我看來,是這樣的

由於我返回一個接口,而不是一個具體的類,WCF不知道會在什麼其他結束。所以,它可以是任何東西。當他得到一份名單時,他感到困惑。
正確的方法是在需要時添加KnownType屬性。
誰需要知道這些類型?服務實現,以正確地序列化和反序列化它們。然而,客戶會與服務的接口進行交談,而不是與實現本身進行交談。這就是爲什麼在服務實現中添加KnownType屬性不起作用
這裏的問題是,接口不允許KnownType屬性,但它們確實允許ServiceKnownType屬性。這個問題的解決辦法是在服務接口契約加上預計類型,瞧,一切工作正常,並使用接口

[ServiceContract] 
    [ServiceKnownType(typeof(Atm))] 
    [ServiceKnownType(typeof(List<Atm>))] 
    public interface IAtmFinderService 
    { 

     [OperationContract] 
     ICollection<IAtm> GetAtms(); 

    } 
+0

+1謝謝你的修復,我有同樣的問題,但只需要添加列表實現我的自定義PagedList實現。我的「T」是一個域對象,並且已經爲我正確序列化。 – Jay 2013-10-22 12:15:58