Cle*_*ems 6 c# wcf dictionary 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" },
}
}
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
谢谢您的回答.我打开了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;
}
}
Run Code Online (Sandbox Code Playgroud)
尝试序列化参数时出错: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.
再次我打得用ServiceKnownType
的ObjectHolder
,ObjectHolder[]
甚至ObjectHolder[][]
因为除了提到的" 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<string, object> GetObject()
Run Code Online (Sandbox Code Playgroud)
另外我建议你不要在服务合同中使用object,因为它非常容易出错.考虑一下,您或您的同事稍后修改一行代码:
new Dictionary<string, object>()
{
{ "pty1", 4 },
{ "pty2", Guid.NewGuid() },
{ "pty3", new SomeClass() }, //OOPS!!!
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,当您的服务尝试返回此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; }
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,如果要添加一些新类型,则应添加工厂方法和KnownTypeAttribute(此方法更详细,但不易出错).
但是,如果您的客户端和服务写在WCF上,您可以牺牲主要的面向服务的原则并使用NetDataContractSerializer而不是DataContractSerializer.NetDataContractSerializer旨在补充DataContractSerializer.您可以使用NetDataContractSerializer序列化类型,并使用DataContractSerializer反序列化.但NetDataContractSerializer在序列化XML中包含CLR类型信息,而DataContractSerializer则不包含.因此,NetDataContractSerializer可以用于任何CLR类型的序列化和反序列化,而不需要任何KnownTypes.