【问题标题】:WCF DataMember Serializing questionsWCF DataMember 序列化问题
【发布时间】:2009-11-13 14:16:05
【问题描述】:

好的,所以我完成了创建 DTO 以通过网络发送我的模型的漫长过程的一部分,但我不觉得我走的是正确的路线。

我的问题是,我模型中的大多数实体无论如何都没有 DTO 多。我基本上有一个贫血的域模型,这很好,但它也让我想知道我是否需要为这些实体建模 DTO。

所以我的第一个问题是,如果只是序列化我的实体并通过网络传递它们,我可能会遇到什么问题?

其次,给出一个更具体的问题,如下所示:

public virtual Unit Unit { get; set; }

我是否可以只通过网络发送 UnitId 而不是序列化的单元对象?

编辑: 抱歉,我的问题不够清楚,正如你们发布的那样,我知道我只能指定单元的 Id 属性,但这对我不起作用。

原因是该属性(上图)位于“Country”类中,我希望 UnitID 仅在调用“CountryService.GetCountry(Id)”或类似名称时返回。但是在流动的服务调用“UnitService.GetUnit(Id)”上,我希望更多的属性被序列化并通过网络发送。 希望这是有道理的。

谢谢,克里斯。

【问题讨论】:

    标签: wcf serialization datamember


    【解决方案1】:

    其次,给出一个更具体的问题,如下所示:

    public virtual Unit Unit { get; set; }

    我是否可以通过电线发送 UnitId 和 不是序列化的单元对象?

    当然 - 确保

    1. 不要用[DataMember] 标记您的Unit 属性
    2. 创建名为UnitId 的第二个属性,您这样做 将其标记为数据成员
    3. 确保您的客户总能以某种方式仅从 UnitId 重构 Unit

    更新:

    原因是这个属性 (上)在“乡村”课上,我 希望 UnitID 仅在我返回时返回 调用“CountryService.GetCountry(Id)” 或类似的。但在流动 服务调用“UnitService.GetUnit(Id)” 我想要更多的属性 序列化并通过网络发送。 希望这是有道理的。

    在这种情况下,您需要两个单独的 DataContract - 一个用于 CountryService.GetCountry(Id) 调用,其中只有 UnitId,另一个用于 UnitService.GetUnit(Id) 调用,其中包含您想要的 Unit 的所有属性它。

    您不能有条件地发送某些属性(或不发送),具体取决于运行时决定。 DataContracts 在 XML 模式中建模,这是相当静态的。如果您需要两组属性,则需要两个单独的 DataContract。

    【讨论】:

      【解决方案2】:

      您可以通过添加 NonSerializedAttribute (msdn) 来缩小将通过线路传递的对象的大小。您仍将获得 Unit,但只能使用 UnitId。

      我认为仅序列化 DTO 不会有问题。 您是否使用了 DTO 中的所有信息? 您是否跨越域边界?我会在每个域中创建新实体并为它们制作映射器。

      【讨论】:

        【解决方案3】:

        据我了解,您的问题源于您有一个由 DTO 制成的本地明确声明的对象图。我的意思是你已经在你的Country 模型上声明了public Unit Unit { get; set; }(不知道你为什么要声明它们virtual,但这与手头的问题没有直接关系),而不是尝试一种保证简单性的方法对象图转化为单个对象图节点的退化情况。

        例如,考虑以public UnitID Unit { get; set; } 的形式在模型上定义每个“引用”属性,其中UnitID 实际上可能是intGuid 或您用来唯一标识的任何内容并区分Unit 模型。无论您在哪里有对另一个模型的引用或一组引用,都将其替换为其标识符类型而不是其实际类型。这种策略非常适合一组持久的模型,例如从/到具有每个模型的身份密钥的数据库。这样做可以让您简化序列化,而不必担心循环引用,因为它们现在是不可能的。从技术上讲,不再有引用(即直接引用;它们现在是间接引用)。我们现在只是在您的域模型设计中添加一个间接层。现在让我们适应那个间接层。

        既然你声称你对贫血域模型方法没问题,那么这应该很适合。您在模型设计中支付间接 (IMHO) 的次要成本,并用它换取基于接口的数据检索方法的主要 (IMHO) 好处:

        public interface IUnitRepository {
            Unit GetUnit(UnitID id);
            IEnumerable<Unit> GetUnits(IEnumerable<UnitID> ids);
            // etc.
        }
        

        在您的消费者代码(即使用此接口的代码和您的Unit 域模型)中,通过执行接口调用以获取间接指向的底层模型,遍历隐含对象图看起来稍微复杂一些参考文献。

        之前:

        Country ct = ...;    // I assume you have this reference already
        Unit ut = ct.Unit;
        

        之后:

        // Somewhere earlier in your code, i.e. not *every* time this type of code appears
        IUnitsRepository repo = new SomeUnitsRepositoryImpl();
        Country ct = ...;    // I assume you have this reference already
        Unit ut = repo.GetUnit(ct.UnitID);
        

        如果这在语法上困扰您,您可以定义一组扩展方法,键入Country 的形式:

        public static Unit Unit(this Country c, IUnitsRepository repo) {
            return repo.GetUnit(c.UnitID);
        }
        

        扩展方法后:

        IUnitsRepository repo = new SomeUnitsRepositoryImpl();
        Country ct = ...;    // I assume you have this reference already
        Unit ut = ct.Unit(repo);
        

        基于接口的方法为您带来一系列经典的好处,例如关注点分离、可测试性、消费者-生产者隔离等等。此外,您现在可以通过接口的实现类型更直接地控制对象的生命周期。我的意思是你不应该假设你的Unit GetUnit(UnitID id) 方法的实现是天真的。此方法现在可以使用与SomeUnitsRepositoryImpl 实例绑定的Dictionary&lt;UnitID, Unit&gt; 执行一些本地内存缓存。

        有点啰嗦,但希望对您有所帮助。好像从所提供的详细信息的数量来看并不明显,我目前正在我的工作地点玩弄这种设计,以处理我们的记录数据库系统。 :) 我真的很喜欢它为我提供的所有灵活性,而代价是在域模型的设计中添加一层间接性。

        【讨论】:

        • 好的,所以属性是虚拟的原因是因为我正在使用 ORM(在这种情况下为 NHibernate),它采用我的 POCO 国家对象并围绕它构建一个代理来自动连接延迟加载相关对象(即本例中的单位)。现在我可以让 Country 对象与您所说的任何其他模型都没有关系,但这意味着手动创建所有这些管道工作。这对我来说不是一个很好的权衡,因为我认为序列化程序应该足够灵活,让我能够采用复杂的模型并且只公开我选择的内容。我最终选择了 AutoMapper
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多