2010-07-26 51 views
6

我想實現一個服務契約,它包含一個採用通用接口的方法,並且該通用接口本身具有一個接口參數。我飾ServiceKnownType服務接口,我都飾有定期KnownType服務實現,我也飾有定期KnownType的datacontract實現:WCF:通用接口的序列化可能嗎?

[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> 
{ 
} 

爲了記錄在案,我有批量那裏,因爲它似乎您只能爲泛型類型表達一次知識類型 - 它似乎會發出BatchOfanyType,但我不知道如何處理此問題。

我得到的異常是「將未知的靜態類型添加到已知類型列表中 - 例如,使用KnownTypeAttribute屬性或將它們添加到傳遞給DataContractSerializer的已知類型列表中。」

有什麼明顯的我做錯了嗎?接口的通用接口是不支持的嗎?爲了記錄,我在這個項目中使用了C#2.0和.NET 3.0。

回答

12

如果您真的想要,您可以在服務合約定義中使用接口,只要您包含已知類型(稍做調整,請參閱下文)即可。

顯然,使用一個接口作爲泛型類型參數對於C#3.0來說是一個橋樑。我將已知的類型屬性更改爲

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

這使得它的工作,到一個點。序列化和反序列化本身會工作,但此時你面對這樣的例外:

無法投類型的對象Batch`1 [命令]' 鍵入「IBatch`1 [ICommand的]」。

對於投射工作,您需要語言支持泛型類型協方差,這是在C#4.0中引入的。對於它在工作C#4.0,雖然,你需要補充方差修改:

public interface IBatch<out T> 
{ 
} 

然後,它完美的作品...不幸的是你不使用C#4.0。

有關在服務合約中使用接口的最後一件事:如果您正在從它們生成服務引用,則會將所有接口參數鍵入爲object,因爲原始接口類型不是元數據的一部分。您可以通過程序集引用共享合同,也可以手動重構生成的代理來修復它,但總而言之,使用與WCF的接口可能比它的價值更麻煩。

+0

是的,當我在C#4.0中考慮協變時,我在使用的平臺中進行了編輯。哦,升級。 – bwerks 2010-07-27 13:34:24

2

WCF是一個基於SOA消息的系統 - 它可以以串行化XML格式發送任何東西,可以用XML模式表達。

不幸的是,XML模式既不知道接口也不知道任何東西,所以沒有 - 你不能一般地序列化這些 - 你需要使用具體的類型。

+0

WCF不理解泛型足夠它們序列化(我已經做到了)。 您在接口上的觀點是正確的。 – RQDQ 2010-07-26 19:28:03

+0

@RQDQ你有展示的地方嗎?一個博客,一個CodeProject文章什麼的?愛看到這一點! – 2010-07-26 19:29:32

+1

@RQDQ:實際上,這不完全正確,imo。雖然接口本身不能被序列化,但使用的具體類型*可以是。 '棘手'部分是反序列化,因爲它需要知道要實例化的具體類型。但是,序列化數據中包含足夠的信息來完成此操作。 – Thorarin 2010-07-26 19:32:50

1

您無法序列化接口。接口只是定義合同,而不是對象。我想這是一個例外是ISerializable接口。

+1

當你「序列化ISerializable」時,你並不是真的。 'ISerializable'是一個用於序列化別的東西的接口。 – 2010-07-26 18:29:33

+0

@John。你是對的。您仍然沒有真正序列化接口,只是同意用於序列化實現ISerializable的對象的協定。我只是爲了完整而添加了這個。 – Mike 2010-07-26 19:11:03

1

泛型可以序列化,但有一定的侷限性。例如,給定的數據合同:

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

,服務合同:

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

,服務實現:

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

服務引用設定爲上述服務後,這代碼可以運行:

ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(); 

ServiceReference1.FooOfstring temp = client.GetData(); 

MessageBox.Show(temp.Value); 

顯示帶有「我的測試字符串」的消息框。

請注意,該服務本身不是通用的,但使用的數據合同是。此外,在客戶端生成的數據合同不是通用的,而是有一個字符串類型的屬性值「扁平化」類:

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