WCF服务返回一个字典<string,object>的数组

我一直在尝试使用SilverLight客户端来调用ASP.Net WCF服务,该服务将返回一个Dictionary<string, object> 。 当字典中的值是像intstringGuid这样的简单类型时,它可以正常工作。

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

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

这是一段代码:

[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>但的一个ArrayDictionary<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。

同样,我打了ServiceKnownTypeObjectHolderObjectHolder[]甚至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)()))>属性。

链接地址: http://www.djcxy.com/p/93551.html

上一篇: WCF service returning an array of dictionary<string, object>

下一篇: Why am I getting 403 frobidden while displaying images on s3?