使用WCF实现契约优先的面向服务架构

12

这个问题更多是探究社区中人们在实践中都在做什么,而不是一个具体针对性的问题。我已经广泛搜索了这方面的信息,虽然找到了很多博客支持先约定后编写服务设计的观点和一些相关评论,但我还没有找到关于如何在 WCF 实现先约定后编写、在现实环境中这样做的优缺点等方面的实用信息。

我的问题如下:

  1. 你如何使用.NET和WCF实现先约定后编写的服务设计?
  2. 除了svcutil之外,是否还有其他工具可以从契约生成客户端和服务端代码?(任何与VS集成的工具都是理想的)
  3. 你在先约定后编写和WCF的实际应用中遇到了哪些优点?
  4. 你在先约定后编写和WCF的实际应用中遇到了哪些缺点?

先约定后编写开发的一个主要问题似乎是工具。Svcutil是我找到的唯一能从契约生成服务代码的工具,它的输出质量相当差。它是单文件的,充斥着属性和代码生成的副产品,而且基本上需要在每次更新契约时重新生成和替换。我希望有更好的方法,最好是不需要重新生成和替换的方法。即使在实际情况下需要手动创建服务端契约,我也没问题。

编辑:

虽然 WCSF 解决了我的直接需求,但了解 Protocol BuffersService Factory 这两个工具都是很有趣的,我相信它们在未来会对我有所帮助。


(回复评论/问题) - Marc Gravell
使用WCSF Blue,我们可以在WSDL中定义自定义策略,然后生成相应的服务端和客户端代码吗? - LCJ
5个回答

15

WSCF 提供了一款集成于VS的合同优先工具。快来查看吧。(免费)

截至7月6日,已发布带安装程序的二进制版本。


谢谢你提供的链接,Chesso。看起来很有前途。然而,在那个CodePlex网站上似乎没有下载链接。你知道在哪里可以下载WCSF.blue吗? - jrista
我们目前正在使用.NET 3.5 SP1和C# 3.0进行开发。这看起来非常有前途。感谢您的建议!如果在赏金期结束之前没有更好的选择,我认为您已经成功了。 :) - jrista
我没意识到有赏金这回事。呵呵。不知道可以用我的积分买些什么!?嗯,什么?……它们一点价值都没有?哦…… - Cheeso
实际上,大约3小时前发布了一个下载。这有多先进啊? - blowdart
我正在相应地更新答案。 - Cheeso
显示剩余3条评论

5

我通常使用契约优先的方法,一般情况下(但不总是)在每一端使用相同的类型表示。

实际上,要使用WCF,您不需要任何特殊的代理等;您可以在两端使用常规的.NET类型,而不使用svcutil.exe。只需将"ABC"添加到配置文件中,然后使用类似以下内容的东西即可获得工作的服务:

public sealed class WcfClient<T> : System.ServiceModel.ClientBase<T>
    where T : class
{
    public T Service { get { return base.Channel; } }
}

现在你可以使用:

using(var client = new WcfClient<IMyService>()) {
    int i = client.Service.SomeMethod("abc");
}

在客户端(和服务器)上,您只有您的IMyService接口。


对于其他工具; protobuf-net是Google的“协议缓冲区”API的实现,它具有用于以“合同优先”(和可移植/互操作)方式描述数据和服务的DSL-例如(.proto文件):

message SearchRequest {
  required string query = 1;
  optional int32 page_number = 2;
  optional int32 result_per_page = 3;
}
message SearchResponse {
  repeated string result = 1; 
}
service SearchService {
  rpc Search (SearchRequest) returns (SearchResponse);
}

“protobuf-net”工具包(由我维护)包括一个“protogen”实用程序,可将此DSL转换为C# / VB;而其中之一的选项(至少适用于C#-我需要检查VB)是发出完整的WCF代理实现(具有您选择的同步或异步方法);与svcutil非常相似-但(由于protobuf-net关系),它在操作契约上包括自定义 [ProtoBehavior] 属性,因此它使用protobuf-net序列化程序而不是 DataContractSerializer (更快,更高效,但不同)。

对于VS集成; 我正在做的就是这个(proof)。


好的,不行。你可以剥离protobuf-net部分,只使用DSL生成WCF代理(很容易做到-只是一个xslt),但这就错过了协议缓冲区的重点...鉴于它在Java、C++、Python上都得到了支持,并且(单独)所有这些:http://code.google.com/p/protobuf/wiki/ThirdPartyAddOns - 但RPC堆栈(通过WCF)不是标准化的;那是实现特定的。 - Marc Gravell
Gocha。如果我理解正确,协议缓冲区基本上是Web服务/WSDL/WS-*标准的替代品,并且更有效,因为它们使用标准二进制序列化?感谢马克的输入。 - jrista
@jrista:是的,二进制序列化是标准的;但目前没有针对此的“标准”RPC;其中有一些方法,包括简单地依赖于WCF。 - Marc Gravell
@约翰:确实,那是一个“精简”版;我的标准实现重新实现了IDisposable,更像这样:http://groups.google.co.uk/group/microsoft.public.dotnet.languages.csharp/msg/552663dfa6be9bf4 - Marc Gravell
我们可以使用svcutil.exe在WSDL中定义自定义策略,然后生成相应的服务端和客户端代码吗? - LCJ
显示剩余5条评论

3
我更喜欢合同优先开发。我已经使用Service Factory来实现这个目的。它允许我生成服务和客户端代码,无需自定义。
通过自定义,我们还能够生成与Entity Framework对象对应的数据传输对象,以及从一个对象转换为另一个对象的代码;自动记录异常日志;以及服务的HTML文档。
除此之外,Service Factory附带的代码分析规则可以帮助防止开发人员选择不兼容的WCF选项而自掘坟墓。

1
我已经稍微使用了Service Factory...在构建时它会生成大量垃圾。可视化合同设计器有点不错,但整个指导包总体上并不是很有效。如果合同设计器更轻便一些,类似于实体框架设计器之类的东西,那就太好了。是否有类似的东西不那么沉重和侵入性? - jrista
我很想知道你所谓的“笨重和繁琐”以及“一堆垃圾”的含义。我曾经深入使用过它,并进行了大量的定制,但我不记得它会生成任何被认为是“垃圾”的东西。我是作为一个需要深入了解代码生成逻辑并学习其工作方式的人来说这番话的。 - John Saunders
1
好的,我没有对代码生成进行任何定制。我在可视化合同设计师上做了很多尝试,最后让它生成代码。结果创建了几个嵌套的解决方案文件夹和近十个项目,其中包括一些测试项目,但对我来说都不是很有用。我们有一个非常庞大的现有基础设施,我希望只能得到一些简单的输出:服务接口、服务实现、数据/消息类型。我没想到会得到十几个项目。 - jrista
好的,是的,它确实会生成自己的解决方案结构,这也是我必须自定义的事情之一。实际上,我最终得到了更多的项目,但都在正确的位置。如果你查看这些项目,你会发现它们生成了正确的代码。它与你自己生成的代码几乎没有什么不同,只是分成了多个项目。 - John Saunders
你可能没有意识到的是,如果您提前知道所有类型的位置,则可以更轻松地实现SF的某些功能。这就是为什么它希望将所有数据合同放入单个项目的原因之一。例如,他们还会处理所有项目间引用,正确设置代码分析设置等。这不是一个快速工具 - 它更像是一种生活方式。 - John Saunders
显示剩余3条评论

2
在WCF中,“contract-first”的形式有所不同。你可以使用“代码契约优先”方式,其中数据和服务契约是使用正确的属性标记表示为.NET类型。你可以从WSDL开始生成服务和数据契约,也可以从XML模式开始定义数据契约,并将服务契约表示为代码。选择哪种方式取决于契约的性质以及它将如何使用。
如果您要按照WSDL规范实现某些内容,则从WSDL进行代码生成是显而易见的选择,手动生成并不是太麻烦。如果您希望WSDL文件的更改立即传播,可以触发项目构建事件(或进入msbuild)来进行生成。
如果您有现有的模式(XSD)要用作数据契约,或者出于在其他平台上更容易重用的考虑,您希望以这种方式开发数据契约,则可以使用xsd.exe(或第三方替代品)从模式生成类型。在这种情况下,您将在面向代码的服务契约中使用可序列化的XML类型,如 this
如果你在.NET中自己开发客户端和服务器,而且你的客户端可以得到你的合同程序集或者从服务元数据(如WSDL)生成客户端,那么用代码建模你的合同是一种很好的体验。使用“已知类型”方案,你可以支持数据合同中的继承模型,这非常强大。通过直接引用合同程序集,你可以完全跳过生成客户端代码(正如其他回复所提到的)。它非常高效、优雅,但你需要意识到,如果你太花哨,会造成互操作挑战。

0

我们实现这个的方式在这个视频中有所描述:

http://www.dnrtv.com/default.aspx?showNum=103

我们的想法是不使用代码生成,因此避免在合同更改时需要重新生成代码。

合同现在以代码形式存在,如果客户端和服务器之间存在不匹配,将会在构建错误中显示出来。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接