2010-02-24 64 views
15

我有這些類:WCF - probem與序列化繼承類型

[DataContract] 
public class ErrorBase {} 

[DataContract] 
public class FileMissingError: ErrorBase {} 

[DataContract] 
public class ResponseFileInquiry 
{ 
    [DataMember] 
    public List<ErrorBase> errors {get;set;}; 
} 

類ResponseFileInquiry的一個實例是我的服務方法返回給客戶端。現在,如果我填ResponseFileInquiry.errors與ErrorBase的情況下,一切工作正常,但如果我添加繼承類型FileMissingError的實例,我序列化過程中得到一個服務端異常:

Type 'MyNamespace.FileMissingError' with data contract name 'FileMissingError' 
is not expected. Add any types not known statically to the list of known types - 
for example, by using the KnownTypeAttribute attribute or by adding them to the 
list of known types passed to DataContractSerializer.' 

所以串行器感到困惑,因爲它期望List包含聲明的類型對象(ErrorBase),但它獲得繼承類型(FileMissingError)對象。

我有一大堆的錯誤類型,列表將包含它們的組合,所以我能做些什麼來使它工作?

回答

17

你應該KnownType屬性添加到您的基類

[DataContract] 
[KnownType(typeof(FileMissingError))] 
public class ErrorBase {} 

瞭解更多關於KnownType屬性在此blog

+1

謝謝,博客條目有所有可能的方式來聲明已知類型。 – Andrey 2010-02-24 21:17:19

+0

在我的情況下,使用KnownType沒有多大幫助,因爲類型來自我沒有引用的單獨程序集。其他開發者正在擴展我爲DataContract添加的一些屬性。如果我只是想拋棄任何派生類並使用基類,該怎麼辦? – brendonparker 2017-02-10 16:31:58

+0

這是我必須使用的解決方案:http:// stackoverflow。com/a/8414390/2460073 注意:我必須將客戶DataContractSerializer應用到ClientBase – brendonparker 2017-02-10 18:50:17

7

試試這個:

[DataContract] 
[KnownType(typeof(FileMissingError))] 
public class ErrorBase {} 

隨着錯誤消息狀態,必須通過屬性來提供,不能靜態地知道(如你在這裏所表達的多態性關係)的任何信息。在這種情況下,您需要指定您的FileMissingError數據協定是其基類的已知類型,即ErrorBase

+0

所以這意味着我需要在這裏指定所有的孩子錯誤類? 有沒有其他的方式呢?我不喜歡這樣一個事實:父類會以附加屬性和類文件中的「使用」子句的方式來注意子類。 該異常說:「將任何未知靜態類型添加到已知類型列表中 - 例如,使用KnownTypeAttribute屬性或將它們添加到傳遞給DataContractSerializer的已知類型列表中。」 那麼有什麼方法可以將它們添加到已知類型的列表中?我怎麼做? – Andrey 2010-02-24 21:10:08

+2

只有在您自己手動序列化合約時,纔可以將已知類型的列表傳遞給序列化。由於看起來好像您允許WCF爲您處理序列化,所以您唯一可以做的就是爲基類添加一個'KnownTypeAttribute',每個子類需要知道它。 – 2010-02-24 21:11:36

2

一個稍微有點晚,但也許後代。 =)

如果你不想爲每個子類的屬性添加到您的父類,你可以在父類的靜態構造函數使用

IEnumerable<Assembly> assemblies = AppDomain.CurrentDomain 
              .GetAssemblies() 
              .Where(a => !a.GlobalAssemblyCache); 

IEnumerable<Type> serializableTypes = assemblies.SelectMany(a => a.GetTypes()) 
               .Where(t => IsSerializable(t)); 

// ... 

private static bool IsSerializable(Type type) 
{ 
    return type.GetCustomAttributes(true).Any(a => a is DataContractAttribute); 
} 

構建已知類型的列表,並通過這列表到de/serializers構造函數。我不知道這個解決方案有多強大,但這就是我正在做的,到目前爲止它的工作原理。它有點慢,所以請確保緩存結果。