【问题标题】:Stop WCF Deserializing Empty ICollection into Zero Capacity Array停止 WCF 将空 ICollection 反序列化为零容量数组
【发布时间】:2014-12-11 05:14:57
【问题描述】:

我在使用 WCF 和 Entity Framework 4.1 POCO 对象(使用 T4 模板生成)时遇到问题。我的基本问题是,当从我的客户端向服务发送 POCO 对象时,WCF 将 ICollection 类型的成员变量反序列化为固定大小的数组。

在客户端,我可以告诉 Visual Studio 使用 IList 而不是 T[] - 但我在服务器端看不到任何类似的选项。

这会导致很多问题,例如将这些对象持久化回数据库。

有没有办法告诉 WCF 将 ICollection(或任何数组)反序列化为什么对象类型?

【问题讨论】:

  • 如果你的成员变量是ICollection 类型导致no end of problems 那么你为什么将它定义为无法处理的东西?即为什么不将它定义为IList,如果那是你的坚持者所期望的。也许详细说明导致下游的问题
  • 因为 POCO T4 模板指定了 ICollection - 我没有手动编写 POCO。作为一项临时措施,我修改了 T4 模板以创建 HashSet 代替它工作正常,但在我看来,它们应该是一种在反序列化指定的泛型/接口类型时指定要使用的具体类型的方法。

标签: wcf serialization entity-framework-4.1


【解决方案1】:

令我感到惊讶的是,没有更多人遇到此问题,因为当您尝试通过 WCF 使用 EF T4 生成的 POCO 对象时,它会让您大吃一惊。具体来说,我得到的错误是这样的:

异常:“无法在实体类型 Datalayer.Customers 上设置字段/属性订单。有关详细信息,请参阅 InnerException。”

InnerException:“无法将项目添加到 'Datalayer.Order[]' 类型的固定大小数组中。”

无论如何,我能想出的唯一解决方案就是您提到的那个,即修改 T4 模板以使用 HashSet 而不是 ICollection。在我看来不是最干净的,但它似乎有效。

【讨论】:

  • 有趣的是,我在相反的方向(服务器到客户端)也有同样的问题。由于客户端无法向固定大小的数组添加或删除行,因此这会带来更多问题。我尝试修改 T4 模板以用 HashSet 替换 ICollection。它不能解决问题。
  • 这听起来可能是您在“添加服务引用”对话框(或 svcutil.exe)中指定的参数有问题。您是否尝试过指定要用作 ObservableCollection 的集合类型?
  • 在“添加服务引用”对话框中使用 System.Collection.Generic.List 而不是 System.Array 作为选定的集合类型解决了这个问题。
  • @omatrot - 如果您从客户端将项目添加到列表中,这将起作用。但是,如果服务器从客户端收到一个列表并且需要在将其保存到数据库之前添加一个项目,您仍然会遇到错误。到那时,您需要处理 T4 模板。 (至少,我想不出任何其他方法。)
【解决方案2】:

我正在使用 Entity Framework 6,我能够通过在我的 T4 模板中进行以下更改来解决此问题。

我将创建导航属性的以下行更改为使用列表而不是来自的集合

navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType,

navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("List<" + endType + ">") : endType,

然后我更改了在构造函数中设置导航属性的代码,通过添加对 .ToList() 的调用将默认哈希集转换为列表。这一行

this.<#=code.Escape(navigationProperty)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>();

改为

this.<#=code.Escape(navigationProperty)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>().ToList();

HashSet.ToList() 方法是一个扩展,因此为了使该扩展方法可用,我通过修改 UsingDirectives 方法添加了 using System.Linq 语句:

    public string UsingDirectives(bool inHeader, bool includeCollections = true)
{
    return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion())
        ? string.Format(
            CultureInfo.InvariantCulture,
            "{0}using System;{1}" + Environment.NewLine +
            "{0}using System.Linq;" + 
            "{2}",
            inHeader ? Environment.NewLine : "",
            includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "",
            inHeader ? "" : Environment.NewLine,
            Environment.NewLine)
        : "";
}

【讨论】:

    猜你喜欢
    • 2022-01-11
    • 2012-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-02
    • 2016-04-12
    • 1970-01-01
    相关资源
    最近更新 更多