2010-01-29 136 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)()))>属性。

相关问题