【问题标题】:Using A WCF Service To Pass An Instantiated Class使用 WCF 服务传递实例化类
【发布时间】:2012-02-09 13:59:23
【问题描述】:

我有一个 C# 类库,其中包含大约 50 个类和数百个属性。实例化我的类可能需要一段时间,因此作为一种优化,我正在考虑让它们在服务器上实例化,然后让服务器通过 WCF 服务将实例化的类传递给客户端应用程序。

似乎它应该可以正常工作。但是,据我了解,如果我想这样做,我不仅需要将每个类标记为[DataContract],还需要将每个属性标记为[DataMember]。这是真的吗?这似乎很疯狂,尤其是在每个财产上。有没有办法说整个类是可序列化的,而不必经过这个过程?

【问题讨论】:

    标签: c# wcf serialization service


    【解决方案1】:

    如果您使用[DataContract],您还需要为每个成员指定[DataMember]

    或者 - 使用[Serializable] 标记类,除非您明确说明,否则序列化程序将为您序列化所有内部结构([Serializable] 用于选择退出方法,而[DataContract] 用于选择加入方法) .

    但是 - 具体取决于您想要做什么 - 这种方法可能存在缺陷。

    当您通过 WCF 传递一个对象时,您根本没有真正传递该对象 - 您传递的是该对象的一个​​副本。事实上,原始对象将被序列化,通过网络传递并在另一端反序列化。这意味着客户端仍然必须实例化 重构类的实例,然后填充所有属性。您可能一无所获,并且可能会通过网络传递大量数据进行相当昂贵的通话。

    所以这一切都取决于你在做什么。如果您不介意客户端获取实例的副本,并且如果费用不是由于数据量太大而是由于数据库访问速度慢等其他原因,那么很好。否则你的方法可能不会给你带来任何好处。

    顺便说一句,在 .Net 远程处理中,可以引用远程对象(即您的客户端可以引用服务器上的对象) - 如果类型本身派生自 MarshalByRefObject,但这不是此处使用 WCF 的情况 - 您最终会在本地获得自己的副本。

    【讨论】:

    • 你没有错 - OP 可能不会在性能方面获得任何好处。但这并没有真正解决他关于使用序列化属性装饰类和属性的问题。
    • 等等……这似乎不对。那么,您是说如果我的客户端应用程序上有以下代码,那么对象的构造函数不仅会在 WCF 服务器上调用,还会在客户端计算机上调用?在我看来,客户端机器应该在没有第二次调用构造函数的情况下获得实例化的副本: MyObject obj = null;静态无效 WCF_SVC_GetMyObjInstCompleted(对象发送者,WCF_SVCRef.GetMyObjInstCompletedEventArgs e){ obj = e.Result; }
    • 我看到你刚刚更新了你的答案。好的,所以我想这样做的原因是因为实例化属性时数据库访问速度慢,而且实例化时必须运行缓慢的初始计算。如果班级已经有人,对我来说会快得多。所以在这种情况下,我会受益,对吧?因为那些不会运行第二次。哦,关于远程处理,我最初打算以这种方式处理它,但我一直在读到 MS 接近弃用远程处理。还是这样吗?谢谢
    • @Yuck - 是的,你是对的 - 我也更新了答案以回答原始问题。
    • @RobLevine +1 但是,在某些情况下,您甚至不需要标记所有类和属性。请参阅我的答案以了解另一种方法 - 解释了注意事项。
    【解决方案2】:

    如果我想这样做,我不仅需要将每个班级标记为 [DataContract] 而且每个属性都为 [DataMember]。这真的是 真的吗?

    是和不是。

    如果客户端代码无法导入包含这些类的程序集,那么,是的,您需要标记它们。这样 WCF 可以告诉客户端如何解释结果集。

    如果您可以在 WCF 服务客户端(例如 POCO 库)中使用通用程序集,则无需应用这些属性。 WCF 只会告诉客户端通过它的强名称来引用程序集。

    这是 WSDL 在案例 #2 中的样子:

    <wsdl:types>
      <xsd:schema targetNamespace = "http://tempuri.org/Imports">
        <xsd:import schemaLocation = "http://localhost:12902/MyService.svc?xsd=xsd0"
           namespace="http://tempuri.org/" />
        <xsd:import schemaLocation = "http://localhost:12902/MyService.svc?xsd=xsd1"
           namespace="http://schemas.microsoft.com/2003/10/Serialization/" />
        <xsd:import schemaLocation = "http://localhost:12902/MyService.svc?xsd=xsd2"
          namespace="http://schemas.datacontract.org/2004/07/MyAssembly.MyProject" />
      </xsd:schema>
    </wsdl:types>
    

    上面的MyAssembly.MyProject 指的是程序集中的命名空间。如果您点击http://localhost:12902/MyService.svc?xsd=xsd2 上的链接(当然是在您的本地计算机上),您将获得一个描述在该命名空间中序列化的实体的 XSD。你不必装饰班级。 WCF 为您完成所有这些工作。

    【讨论】:

    • 这就是你的意思吗?我有一个生成 dll 的类库。我将 dll 包含到客户端应用程序的项目中,并将 dll 包含到 wcf 服务的项目中。如果我这样做,那么我就不必在类库中的类上标记 datacontract 或 datamember,但我仍然可以通过 wcf 服务从它传递一个实例化类?
    • @Nullqwerty 没错。但是有一些限制。应该很明显,但这种方法仅适用于使用 Visual Studio 导入服务引用时自动生成的 .NET 提供给您的客户端类。如果你有其他东西在消费服务,你必须使用用属性装饰类的方法。我会更新我的答案...
    • "这种方法仅适用于使用 Visual Studio 导入服务引用时自动生成的 .NET 提供给您的客户端类" .... 嗯,这很有意义,因为我实际上有首先尝试了这个,我在服务调用中遇到了错误。但是我使用的客户端对象是类库中的类型,而不是自动生成的类。有趣...我将不得不考虑这种方法的含义,因为客户端应用程序已经是一个成熟的产品并且它相当大,因此可能会有很多变化。感谢您的帮助!
    • @Nullqwerty 是的 - 你会使用 AutoMapper 之类的东西来弥合差距。如果你能生活在这些限制内,WCF 确实为你做了很多繁重的工作。
    • 谢谢你!如果我可以将 2 个答案标记为已接受的答案,那么您的答案同样有用,但只是一种不同的方法。再次感谢
    【解决方案3】:

    基本上是的。它需要在类、结构和字段上具有两个属性,以便 NET 知道序列化这些类。如果没有这些属性,这些属性将不会被序列化,并且您将不会在客户端中看到该字段或类。

    【讨论】:

      【解决方案4】:

      在真正独立的客户端服务器场景中,您必须这样做。 (如果您无法共享文件。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-17
        • 1970-01-01
        • 1970-01-01
        • 2013-01-09
        相关资源
        最近更新 更多