WCF服务返回一个字典数组< string,object> [英] WCF service returning an array of dictionary<string, object>

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

问题描述

我一直在尝试使用SilverLight客户端来调用一个ASP.Net WCF服务,它返回一个 Dictionary< string,object>
当字典中的值是简单的类型,如 int string Guid

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.

但是,我现在有一个场景,我需要一个值为字典< string,object> !所有的编译都很好,服务的签名没有改变,但服务调用现在失败。

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.

任何想法如何解决?我尝试使用 KnownType ServiceKnownType 属性注释我的服务类和方法,但没有起作用。

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.

这是一段代码:

[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 code>字典< string,object> 。

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>.

这里由WCF服务记录的例外。

Here the exception logged by WCF service.


尝试序列化参数时出现错误: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了解更多详细信息。

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.

我还尝试定义一个新的 DataContract class与单个数据成员,但它导致相同的错误。

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

这是代码,其次是WCF日志记录的异常。 / p>

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




有一个错误而尝试序列化参数: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了解更多详情。

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.

再次使用 ServiceKnownType 对于 ObjectHolder ObjectHolder [] 甚至 ObjectHolder [] [] 因为异常提到了一个 ArrayOfArrayOfKeyValueOfstringObjectHolder

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

仍然没有解决方案。

推荐答案

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

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.

现在,让我们尝试解决您的问题。我几乎相信这个问题在已知的类型。在面向服务的世界中,您应该手动定义可以参与服务合同的所有具体类型,因为DataContractSerializer不会在序列化对象中提供此类信息。

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!!!
}

在这种情况下,当您的服务尝试返回此字典时,遇到运行时故障因为DataContractSerializer不期望本合同中的SomeClass。

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

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

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).

但是,如果您的客户端和服务在WCF上编写,您可以牺牲主要的面向服务的原则并使用 NetDataContractSerializer 而是 DataContractSerializer 。 NetDataContractSerializer旨在补充DataContractSerializer。您可以使用NetDataContractSerializer序列化一个类型,并使用DataContractSerializer进行反序列化。但NetDataContractSerializer在序列化XML中包含CLR类型信息,而DataContractSerializer则不包含。因此,NetDataContractSerializer可以在任何CLR类型的序列化和反序列化中使用,没有任何KnownType类型。

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; string,object&gt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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