WCF服务返回一个字典<string,object>的数组
我一直在尝试使用SilverLight客户端来调用ASP.Net WCF服务,该服务将返回一个Dictionary<string, object>
。 当字典中的值是像int
, string
或Guid
这样的简单类型时,它可以正常工作。
但是,我现在有一个场景,我需要其中一个值为Dictionary<string, object>
的数组! 这一切都编译好,服务的签名没有改变,但现在服务调用失败。
任何想法如何解决它? 我试图使用KnownType
和ServiceKnownType
属性来注释我的服务类和方法,但这不起作用。
这是一段代码:
[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>
但的一个Array
的Dictionary<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, Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]] []'与数据协定名称'ArrayOfArrayOfKeyValueOfstringObjectHolderWAwxSTlb:http://schemas.microsoft.com/2003/10/Serialization/Arrays'不是预期的。 将任何未知的静态类型添加到已知类型列表中 - 例如,使用KnownTypeAttribute属性或将它们添加到传递给DataContractSerializer的已知类型列表中。 有关更多详细信息,请参阅InnerException。
同样,我打了ServiceKnownType
为ObjectHolder
, ObjectHolder[]
甚至ObjectHolder[][]
因为除了提到的“ ArrayOfArrayOfKeyValueOfstringObjectHolder
”。
仍然没有解决方案。
首先,您应该在应用程序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<string, object> GetObject()
另外我建议你不要在服务契约中使用对象,因为它非常容易出错。 考虑一下,稍后你或你的一位同事修改一行代码:
new Dictionary<string, object>()
{
{ "pty1", 4 },
{ "pty2", Guid.NewGuid() },
{ "pty3", new SomeClass() }, //OOPS!!!
}
在这种情况下,当您的服务试图返回此Dictionary时,您会遇到运行时失败,因为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()
数组,你必须明确地将这个整型数组添加到已知的服务类型中。
<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)()))>
属性。
上一篇: WCF service returning an array of dictionary<string, object>
下一篇: Why am I getting 403 frobidden while displaying images on s3?