WCF服务返回的字典&LT的数组;字符串对象> [英] WCF service returning an array of dictionary<string, object>

查看:413
本文介绍了WCF服务返回的字典&LT的数组;字符串对象>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在试图用一个Silverlight客户端调用一个ASP.Net WCF服务,将返回词典<字符串对象>
这正常工作时,在字典中的值是简单的类型,如 INT 字符串的Guid

不过,我现在有一种情况,我需要的值之一为的数组字典<字符串对象> !这一切编译罚款和服务的签名没有改变,但在服务调用现在失败。

任何想法如何解决?我想我的标注服务类,并与 KnownType ServiceKnownType 属性,但是没有奏效的方法。

下面是一块code的:

  [的ServiceContract(命名空间=)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)
公共类服务1
{
    [OperationContract的]
    [ServiceKnownType(typeof运算(字典<字符串对象>))]
    公共字典<字符串对象> GetObject的()
    {
        返回新字典<字符串对象>()
            {
                {pty1,1},
                {pty2,Guid.NewGuid()},
                {pty3,嗒嗒},
                {pty4,新的字典<字符串对象> []
                              {
                                  新字典<字符串对象>()
                                      {
                                          {pty1,4},
                                          {pty2,Guid.NewGuid()},
                                          {pty3,嗒嗒},
                                      }
                                   ,
                                   新字典<字符串对象>()
                                      {
                                          {pty1,4},
                                          {pty2,Guid.NewGuid()},
                                          {pty3,blahblah},
                                      }
                              }
            }
        };
    }
}

感谢您的答案。我打开WCF的跟踪,并为疑似,有序列化过程中出现问题。
问题不在于词典&LT的系列化;字符串对象> ,但 之一>词典<字符串对象>

下面通过WCF服务记录异常。


  

有尝试序列化参数的错误:GetObjectResult。该消息的InnerException是'类型'System.Collections.Generic.Dictionary`2 [System.String,mscorlib程序,版本= 2.0.0.0,文化=中性公钥= b77a5c561934e089],[System.Object的,mscorlib程序,版本为2.0。 0.0,文化=中性公钥= b77a5c561934e089]] []'数据合同名称'ArrayOfArrayOfKeyValueOfstringanyType: http://schemas.microsoft.com/2003/10/Serialization/Arrays 的'不期望。添加不是静态已知的已知类型的列表中的任何类型 - 例如,通过使用KnownTypeAttribute属性或通过将其添加到已知类型传递给DataContractSerializer列表'。请参阅的InnerException了解更多详情。


我也尝试定义一个单一的数据成员的新 DataContract 类,但它会导致非常相同的错误。

下面是code代表的是,随后通过WCF测井记录的异常。

  [DataContract]
[KnownType(typeof运算(的ObjectHolder))]
公共类的ObjectHolder
{
    [数据成员]
    公共对象的对象{搞定;私人集; }    公众的ObjectHolder(obj对象)
    {
        this.Object = OBJ;
    }
}


  

有尝试序列化参数的错误:GetObjectResult。该消息的InnerException是'类型'System.Collections.Generic.Dictionary`2 [System.String,mscorlib程序,版本= 2.0.0.0,文化=中性公钥= b77a5c561934e089],[SilverlightApplication7.Web.ObjectHolder,SilverlightApplication7.Web,版本= 1.0.0.0,文化=中立,公钥=空] []'数据合同名称'ArrayOfArrayOfKeyValueOfstringObjectHolderWAwxSTlb:的 http://schemas.microsoft.com/2003/10/Serialization/Arrays 。添加不是静态已知的已知类型的列表中的任何类型 - 例如,通过使用KnownTypeAttribute属性或通过将其添加到已知类型传递给DataContractSerializer列表'。请参阅的InnerException了解更多详情。


同样,我打了 ServiceKnownType 的ObjectHolder 的ObjectHolder [] ,甚至的ObjectHolder [] [] 由于异常提到的 ArrayOfArrayOfKeyValueOfstringObjectHolder

仍然没有解决呢。


解决方案

首先你应该配置WCF在应用cofig文件跟踪,可以帮助您了解业务通信的引擎盖下是什么happends。在这种情况下,你就可以轻松搞定,在通信过程中发生的所有错误。

现在,让我们试着解决你的问题。我几乎相信在已知类型的问题。在面向服务的世界里,你必须手动定义所有的具体类型可以参与服务合同,因为DataContractSerializer的不序列化对象提供这些信息。

在此情况下,它的意思是,你应该做以下几点:

  [ServiceKnownType(typeof运算(字符串))
[ServiceKnownType(typeof运算(GUID))]
[ServiceKnownType(typeof运算(INT))] //但我认为的DataContractSerializer可以处理自己与原语
[ServiceKnownType(typeof运算(YourClass))//用户定义的类型,你应该手动添加
公共字典<字符串对象> GetObject的()

此外,我建议你不要在服务合同使用对象,因为它非常容易出错。想想,以后你或你的一个同事修改code的一行:

 新字典<字符串对象>()
{
 {pty1,4},
 {pty2,Guid.NewGuid()},
 {pty3,新的SomeClass的()} // OOPS!
}

在这种情况下,当你的服务尝试返回该字典您遇到运行时失败,因为DataContractSerializer的不本合同预计SomeClass的。

要解决这个问题的一种方法是创建分离型:

  [DataContract]
[KnownType(typeof运算(GUID))]
[KnownType(typeof运算(SomeClass1))]
[KnownType(typeof运算(SomeClass2))]
公共类的MyType
{
  私人的MyType(obj对象){
     对象= OBJ;
  }  公共静态的MyType FromSomeClass1(SomeClass1 C1){
    返回新的MyType(C1);
  }  公共静态的MyType FromSomeClass2(SomeClass2 C2){
    返回新的MyType(C2);
  }  公共静态的MyType FromGuid(GUID GUID){
    返回新的MyType(GUID);
  }  [数据成员]
  公共对象的对象{搞定;私人集; }
}

在这种情况下,如果你想添加一些新的类型,你应该添加工厂方法和KnownTypeAttribute(这种方法更详细的,但不容易出错)。

不过,如果你的客户端和服务写在WCF,你可以牺牲主要服务至上的原则,并使用<一个href=\"http://msdn.microsoft.com/en-us/library/system.runtime.serialization.netdatacontractserializer%28VS.100%29.aspx\">NetDataContractSerializer而不是<一href=\"http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer.aspx\">DataContractSerializer. NetDataContractSerializer旨在补充DataContractSerializer的。您可以使用NetDataContractSerializer序列化类型和反序列化DataContractSerializer的。但NetDataContractSerializer包括序列化的XML CLR类型的信息,而DataContractSerializer的没有。因此,NetDataContractSerializer在序列化和反序列化与任何CLR类型使用没有任何东西KnownTypes

I've been trying to use a SilverLight client to call an ASP.Net WCF service that would return a Dictionary<string, object>. That worked fine when the values in the dictionary were simple types like int, string or Guid.

However, I now have a scenario where I need one of the values to be an array of Dictionary<string, object>! It all compiles fine and the signature of the service has not changed but the service call now fails.

Any ideas how to fix it? I've trying to annotate my service class and methods with the KnownType and ServiceKnownType attributes but that didn't work.

Here is a piece of code:

[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" },
                                      }
                              }
            }
        };
    }
}

Thank you for your answers. I've turned on WCF tracing and, as suspected, there is a problem during serialization. The problem is not the serialization of Dictionary<string, object> but the one of Array of Dictionary<string, object>.

Here the exception logged by WCF service.

There was an error while trying to serialize parameter :GetObjectResult. The InnerException message was '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]][]' with data contract name 'ArrayOfArrayOfKeyValueOfstringanyType:http://schemas.microsoft.com/2003/10/Serialization/Arrays' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.

I've also try to define a new DataContract class with a single data member but it lead to the very same error.

Here is the code for that, followed by the exception logged by WCF logging.

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

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

There was an error while trying to serialize parameter :GetObjectResult. The InnerException message was '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]][]' with data contract name 'ArrayOfArrayOfKeyValueOfstringObjectHolderWAwxSTlb:http://schemas.microsoft.com/2003/10/Serialization/Arrays' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.

Again I've played with ServiceKnownType for ObjectHolder, ObjectHolder[] and even ObjectHolder[][] since the exception mentions an "ArrayOfArrayOfKeyValueOfstringObjectHolder".

Still no solution yet.

解决方案

First of all you should configure WCF tracing in app cofig file that can help you to understand what happends under the hood of service communications. In this case you can easily get all errors that occurs during communication process.

Now, lets try to solve your problem. I almost confident that problem in in known types. In service-oriented world you should manually define all concrete types that can participate in service contract, because DataContractSerializer doesn't provide such information in serialized objects.

In this case it mean, that you should do following:

[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()

Also I recommended to you do not use object in service contract because it VERY error prone. Consider, that later you or one of your colleagues modifies one line of code:

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

In this case, when your service tries to return this Dictionary you encounter runtime failure because DataContractSerializer doesn't expect SomeClass in this contract.

One way to solve this problem is to create separate type:

[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; }
}

In this case if you want to add some new type, you should add factory method and KnownTypeAttribute (this approach more verbose, but less error prone).

However, if your client and service written on WCF, you can sacrifice main service-oriented principles and use NetDataContractSerializer instead DataContractSerializer. NetDataContractSerializer is designed to complement DataContractSerializer. You can serialize a type using NetDataContractSerializer and deserialize with DataContractSerializer. But NetDataContractSerializer includes CLR type information in the serialized XML, whereas the DataContractSerializer does not. Therefore, the NetDataContractSerializer can used in serialization and deserialization with any CLR types without any KnownTypes stuff.

这篇关于WCF服务返回的字典&LT的数组;字符串对象&gt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆