WCF服务返回字典数组

我一直在尝试使用SilverLight客户端来调用ASP.Net WCF服务,该服务将返回Dictionary 。 当字典中的值是intstringGuid等简单类型时,这很好用。

但是,我现在有一个场景,我需要其中一个值为Dictionary的数组! 这一切都编译得很好,服务的签名没有改变,但服务调用现在失败了。

任何想法如何解决它? 我试图使用KnownTypeServiceKnownType属性来注释我的服务类和方法,但这不起作用。

这是一段代码:

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

谢谢您的回答。 我已经启用了WCF跟踪,并且正如所怀疑的那样,序列化期间存在问题。 问题不在于Dictionary的序列化,而是DictionaryArray之一。

这是WCF服务记录的exception。

尝试序列化参数时出错: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日志记录的exception。

 [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, Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]] []’,数据协定名称为“ArrayOfArrayOfKeyValueOfstringObjectHolderWAwxSTlb: http : //schemas.microsoft.com/2003/10/Serialization/Arrays ”,不是预期的。 将任何静态未知的类型添加到已知类型列表中 – 例如,通过使用KnownTypeAttribute属性或将它们添加到传递给DataContractSerializer的已知类型列表中。 有关更多详细信息,请参阅InnerException。

我再次使用ObjectHolderObjectHolder[]甚至ObjectHolder[][] ServiceKnownType ,因为exception提到了“ ArrayOfArrayOfKeyValueOfstringObjectHolder ”。

还没有解决方案。

首先,您应该在app cofig文件中配置WCF跟踪,以帮助您了解服务通信的内容。 在这种情况下,您可以轻松获取通信过程中发生的所有错误。

现在,让我们尝试解决您的问题。 我几乎对已知类型的问题充满信心。 在面向服务的世界中,您应手动定义可以参与服务契约的所有具体类型,因为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 GetObject() 

另外我建议你不要在服务合同中使用对象,因为它非常容易出错。 考虑一下,您或您的同事之后修改一行代码:

 new Dictionary() { { "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。

尝试定义一个具有单个属性的类。 该属性是字符串,对象的字典。

使用DataContract / DataMember标记类。 然后使用该类定义您的接口。

但是,我现在有一个场景,我需要其中一个值为字典数组!

问题是WCF不知道如何序列化/反序列化未标记DataMember属性和/或未添加到ServiceKnownType的对象数组。

例如,如果存在某种服务方法,则将任意对象作为参数

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

并且你想传递一个整数数组Integer() ,你必须显式地添加这个整数类型数组来服务已知类型。

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

然后可以调用服务方法

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

任何想法如何解决它?

尝试添加属性。