【问题标题】:Application structure using WCF使用 WCF 的应用程序结构
【发布时间】:2009-12-11 12:04:21
【问题描述】:

我有一个 WPF 应用程序,到目前为止它只是客户端,但现在我正在努力将其拆分为客户端和服务器端。在这项工作中,我介绍了用于客户端-服务器通信的 WCF。我的应用程序有多个项目,并且需要来自多个项目的服务引用。

进行分离的最初努力是“直截了当地”做所有事情。所有需要与服务通信的项目都会获得一个服务引用,主 WPF 应用程序项目也是如此——在那里获取 app.config。我发现这很快就会变成一团糟,我无法想象这是人们使用的典型架构?我还看到每个服务引用都会生成 DataContract 类的新实现这一事实的问题——因此对跨项目的 DataContract 类没有共同的理解。我在一个项目中有一些 ViewModel 类,另一个项目实例化了一些 ViewModel。我想传递从服务接收到的对象,但我不能传递接收到的对象的生成的客户端表示在每个项目中都不同。

那么 - 有没有推荐的方法来使用 WCF 构建这种客户端/服务器分离?还是要遵循的原则?我在想一个在客户端使用的通用代理项目,它与服务进行通信,包装接收到的数据,并以客户端库熟知的表单返回数据。应该只提供一个服务参考,我想我只需要 wpfApp-project 中的 App.config 吗?这有意义吗?

【问题讨论】:

    标签: .net wcf architecture structure


    【解决方案1】:

    我喜欢这样构建我的 WCF 解决方案:

    合同(类库)
    包含所有服务、操作、故障和数据合同。可以在纯 .NET-to-.NET 场景中在服务器和客户端之间共享

    服务实现(类库)
    包含实现服务的代码,以及实现此目的所需的任何支持/帮助方法。没有别的了。

    服务主机(可选 - 可以是 Winforms、控制台应用程序、NT 服务)
    包含用于调试/测试或可能还用于生产的服务主机。

    这基本上给了我服务器端的东西。

    在客户端:

    客户端代理(类库)
    我喜欢将我的客户端代理打包到一个单独的类库中,这样它们就可以被多个实际的客户端应用程序重用。这可以使用 svcutil 或“添加服务引用”并手动调整生成的可怕的 app.config 来完成,或者通过使用 ClientBase<T>ChannelFactory<T> 构造手动实现客户端代理(共享合同程序集时)。

    1-n 个实际客户(任何类型的应用)
    通常只会引用客户端代理程序集,或者也可能会引用合同程序集,如果它被共享的话。这可以是 ASP.NET、WPF、Winforms、控制台应用程序、其他服务 - 你可以命名它。

    这样;我有一个漂亮而干净的布局,我一遍又一遍地使用它,我真的认为这让我的代码更干净,更容易维护。

    这受到了 Miguel Castro 在 DotNet Rocks TV 上与 Carl Franklin 合作的 Extreme WCF screen cast 的启发 - 强烈推荐屏幕演员!

    【讨论】:

    • 感谢您提供非常好的答案!回几个问题:拥有一个服务主机,您需要在启动应用程序时同时启动主机和客户端?或者有什么办法可以解决这个问题?关于客户端代理 - 您更喜欢哪个?手动 impl 听起来更加一致,因为您不必处理过期的服务引用..
    • @bambuska:当然,您必须同时启动服务主机和客户端才能进行测试;在 Visual Studio 中选择“启动多个项目”来实现这一点 - 您可以在按 F5 时启动服务主机和客户端。
    • 客户端代理:我喜欢手动实现客户端代理时拥有的完全控制权——尽管我可以在服务器和客户端之间共享合同(因为客户端代理的手动实现必须有权访问实际合同)
    • 关于测试 - 您可以添加对服务实现的引用并使用实现类而不是代理。一旦一切正常,删除对服务实现的引用并返回使用代理。
    • +1 链接到 Extreme WCF 屏幕投射 - 值得花时间观看。
    【解决方案2】:

    这取决于。 WCF 是一个大型框架,它旨在跨越许多不同的场景。

    但是对于像您这样简单的应用程序,当您不关心 Java 互操作或通用 Web 服务互操作之类的东西时,我会这样做:

    所有 DataContract 类和 ServiceContract 接口都进入一个在客户端和服务器之间共享的库(或多个库)中。请注意,您可能不应该使用 ServiceContract 来装饰您的服务实现,您应该使用可以放入共享程序集中的 ServiceContract 属性创建一个单独的接口。

    所以你似乎做的一切都是正确的。在这种情况下,您可能根本不需要自动生成代理。那只会让你痛苦。因此,不要使用“添加服务引用”对话框来执行您正在执行的操作。只需包含您共享的 DataContract 程序集并使用 ChannelFactory 来获取共享库中定义的服务接口的代理。这也使您不必继续在 Visual Studio 中重新生成代理,对于任何大小合适的项目,代理都会变得非常快。

    如果您采用这条路线,您还可以摆脱 MetaDataExchange 端点,因为只需要向客户端描述服务。由于您在共享程序集中执行所有操作,因此您不需要服务描述,因为您已经拥有代码形式的服务描述。

    【讨论】:

    • 谢谢!这听起来很吸引人。自动生成的代理确实已经引起了痛苦......我实际上正在尝试与您已经描述的类似的实现,但是当我想要异步服务时它停止了。我也可以轻松使用 ChannelFactory 生成异步服务吗?
    • 哦,JavaInterop 等根本不相关。这将是所有 .net 到 .net!将 DataContracts 放在共享库中,我实际上可以返回,例如来自服务的 MyClass 对象,它与接收到的类型完全相同?
    【解决方案3】:

    我常用的结构是:

    Common - 包含接口、数据契约、服务契约、抽象类等; Client——引用Common,包含服务器代理类; 服务器 - 引用 Common,包含实际的实现类;

    【讨论】:

    • 同意。虽然我经常让公共库包含可以在服务双方使用的 DTO,然后不使用生成的代理类。
    • 听起来我需要有一个共享项目的共同项目..!你是在使用自动生成的代理,还是忽略那些——比如@asgerhallas?当然,如果可以的话,我想我想省略使用它们。他们已经造成了太多的痛苦..
    • 我从 ClientBase 派生代理类并实现接口以将调用转发到 Channel。
    • 听起来不错。您是否也可以实现从 ClientBase 派生的异步服务,或者我必须改用 ClientFactory 吗?如果我理解正确,服务应该在服务器端异步 - 在这种情况下,我想这不会有什么不同?..
    • 您可以实现异步服务。只需创建 beginX 和 endX 方法(在接口、实现和代理中)。
    猜你喜欢
    • 2012-08-25
    • 2010-10-17
    • 2012-06-16
    • 1970-01-01
    • 2023-03-05
    • 2011-08-16
    • 1970-01-01
    • 2013-02-11
    • 2018-01-28
    相关资源
    最近更新 更多