2010-01-29 87 views
6

我一直在嘗試使用SilverLight客戶端來調用返回Dictionary<string, object>的ASP.Net WCF服務。 當字典中的值是簡單類型如int,stringGuid時,它工作正常。WCF服務返回字典數組字符串<string,object>

但是,我現在有一個場景,我需要其中一個值爲Dictionary<string, object>的數組!這一切都編譯好,服務的簽名沒有改變,但現在服務調用失敗。

任何想法如何解決它?我試圖使用KnownTypeServiceKnownType屬性註釋我的服務類和方法,但這不起作用。

下面是一段代碼:

[ServiceContract(Namespace = "")] 
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] 
public class Service1 
{ 
    [OperationContract] 
    [ServiceKnownType(typeof(Dictionary<string, object>))] 
    public Dictionary<string, object> GetObject() 
    { 
     return new Dictionary<string, object>() 
      { 
       { "pty1", 1 }, 
       { "pty2", Guid.NewGuid() }, 
       { "pty3", "blah" }, 
       { "pty4", new Dictionary<string, object>[] 
           { 
            new Dictionary<string, object>() 
             { 
              { "pty1", 4 }, 
              { "pty2", Guid.NewGuid() }, 
              { "pty3", "blah" }, 
             } 
            , 
            new Dictionary<string, object>() 
             { 
              { "pty1", 4 }, 
              { "pty2", Guid.NewGuid() }, 
              { "pty3", "blahblah" }, 
             } 
           } 
      } 
     }; 
    } 
} 

謝謝您的解答。我已經打開WCF跟蹤,並懷疑在序列化過程中出現問題。 問題不在於Dictionary<string, object>的序列號,而是ArrayDictionary<string, object>的序列號。

這裏是WCF服務記錄的異常。

嘗試序列化參數:GetObjectResult時發生錯誤。 InnerException消息是'Type'System.Collections.Generic.Dictionary`2 [[System.String,mscorlib,Version = 2.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089],[System.Object,mscorlib,Version = 2.0。 0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]] []'與數據協定名稱'ArrayOfArrayOfKeyValueOfstringanyType:http://schemas.microsoft.com/2003/10/Serialization/Arrays'不是預期的。將任何未知的靜態類型添加到已知類型列表中 - 例如,使用KnownTypeAttribute屬性或將它們添加到傳遞給DataContractSerializer的已知類型列表中。有關更多詳細信息,請參閱InnerException。

我也嘗試用單個數據成員來定義一個新的DataContract類,但它導致了非常相同的錯誤。

下面是該代碼,然後是由WCF日誌記錄記錄的異常。

[DataContract] 
[KnownType(typeof(ObjectHolder))] 
public class ObjectHolder 
{ 
    [DataMember] 
    public object Object { get; private set; } 

    public ObjectHolder(object obj) 
    { 
     this.Object = obj; 
    } 
} 

而試圖序列參數時出現錯誤:GetObjectResult。 InnerException消息是'Type'System.Collections.Generic.Dictionary`2 [[System.String,mscorlib,Version = 2.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089],[SilverlightApplication7.Web.ObjectHolder,SilverlightApplication7.Web,版本= 1.0.0.0,Culture = neutral,PublicKeyToken = null]] []'與數據協定名稱'ArrayOfArrayOfKeyValueOfstringObjectHolderWAwxSTlb:http://schemas.microsoft.com/2003/10/Serialization/Arrays'不是預期的。將任何未知的靜態類型添加到已知類型列表中 - 例如,使用KnownTypeAttribute屬性或將它們添加到傳遞給DataContractSerializer的已知類型列表中。有關更多詳細信息,請參閱InnerException。

再次我打了ServiceKnownTypeObjectHolderObjectHolder[]甚至ObjectHolder[][]因爲除了提到的「ArrayOfArrayOfKeyValueOfstringObjectHolder」。

還沒有解決方案呢。

+0

您收到什麼錯誤? – 2010-01-29 05:24:56

+0

我的猜測是WCF可能會麻煩串行化對象。如果可行,你可以嘗試製作你的字典。 – sipwiz 2010-01-29 05:38:30

+0

我同意sipwiz,你會有麻煩序列化字典。你應該讓Dictionary包含一個可序列化的對象(這意味着你需要通過Dictionary srodriguez 2010-01-29 05:54:29

回答

0

嘗試定義一個具有單個屬性的類。該屬性是一個字符串,對象的字典。

用DataContract/DataMember標記類。然後使用該類定義你的接口。

8

首先您應該在應用程序cofig文件configure WCF tracing,可以幫助您瞭解什麼發生在服務通信的引擎蓋下。在這種情況下,您可以輕鬆獲取通信過程中發生的所有錯誤。

現在,讓我們試着解決你的問題。我幾乎相信這種已知類型的問題。在面向服務的世界中,您應手動定義可參與服務合約的所有具體類型,因爲DataContractSerializer不會在序列化對象中提供此類信息。

在這種情況下,它的意思是,你應該做以下:

[ServiceKnownType(typeof(string))] 
[ServiceKnownType(typeof(Guid))] 
[ServiceKnownType(typeof(int))] // but I think DataContractSerializer can deal himself with primitives 
[ServiceKnownType(typeof(YourClass))] //UserDefined types you should add manually 
public Dictionary<string, object> GetObject() 

此外,我建議你不要在服務合同使用對象,因爲它非常容易出錯。想想,以後你或你的同事修改一行代碼:

new Dictionary<string, object>() 
{ 
{ "pty1", 4 }, 
{ "pty2", Guid.NewGuid() }, 
{ "pty3", new SomeClass() }, //OOPS!!! 
} 

在這種情況下,當你的服務試圖返回該字典,你遇到運行時失敗,因爲DataContractSerializer的並不在此合同預計SomeClass的。要解決這個問題

一種方法是創建單獨的類型:

[DataContract] 
[KnownType(typeof(Guid))] 
[KnownType(typeof(SomeClass1))] 
[KnownType(typeof(SomeClass2))] 
public class MyType 
{ 
    private MyType(object obj) { 
    Object = obj; 
    } 

    public static MyType FromSomeClass1(SomeClass1 c1) { 
    return new MyType(c1); 
    } 

    public static MyType FromSomeClass2(SomeClass2 c2) { 
    return new MyType(c2); 
    } 

    public static MyType FromGuid(Guid guid) { 
    return new MyType(guid); 
    } 

    [DataMember] 
    public object Object { get; private set; } 
} 

在這種情況下,如果你想添加一些新的類型,你應該添加工廠方法和KnownTypeAttribute(這種方法更詳細的,但不容易出錯)。

但是,如果您的客戶端和服務寫在WCF上,您可以犧牲主要服務導向原則並使用NetDataContractSerializer而不是DataContractSerializer。 NetDataContractSerializer旨在補充DataContractSerializer。您可以使用NetDataContractSerializer序列化一個類型,並使用DataContractSerializer反序列化。但NetDataContractSerializer在序列化XML中包含CLR類型信息,而DataContractSerializer則不包含。因此,NetDataContractSerializer可以用於任何CLR類型的序列化和反序列化,而不需要任何KnownTypes。

+0

這是最好的答案,你可以通過指出它不是未知類型的字典,而是包含在字典中的對象類型來改進它,這就是爲什麼添加[ServiceKnownType(在添加[ServiceKnownType(typeof(types_which_the_object_might_be)]時,typeof(Dictionary ))]不起作用。 – 2015-11-18 21:56:02

0

但是,我現在有一個場景,我需要其中的一個值爲字典數組!

的問題是,WCF不知道如何串行器/反序列化沒有標記DataMember屬性和/或不被添加到ServiceKnownType的S對象的陣列。

例如,如果有一些服務方法,它接受一個任意對象作爲參數

public interface IService 
    function DoSomething(Parameter as Object) as integer 
end interface 

,並要傳遞,說整數Integer()數組,你必須明確地添加此整數數組鍵入以服務已知類型。

<ServiceKnownType(GetType(Integer()))> 
public interface IService 
    function DoSomething(Parameter as Object) as integer 
end interface 

然後服務方法可稱爲

dim Service as IService 
dim Argument as Integer() 
Service.DoSomething(Argument) 

任何想法如何解決呢?

嘗試添加<ServiceKnownType(GetType(Dictionary(Of String, Object)()))>屬性。

相關問題