WCF/WF 的 WS-Enumeration






4.86/5 (5投票s)
在本文中,我将介绍 WCF 的 WS-Enumeration 的设计和实现。
引言
本文可以看作是 Roman Kiss 撰写的《用于工作流的 WS-Transfer 服务》文章的延续。我根据 Roman Kiss 提出的方法实现了 WS-Enumeration 规范。利用顺序工作流进行服务或协议开发对我很有吸引力,因为这是一种非常自然的方式。在许多情况下,你只需查看图表就能理解服务或协议的运行方式。
WS-Enumeration 的目的是枚举不同结构(可以是列表、树等)中的元素。因此,人们可能会认为 LINQ 会很有帮助。想到这一点,我回忆起 Colin Eberhardt 撰写的《LINQ to Tree - 查询树状结构的通用技术》一文。Colin 的主要想法是将“LINQ to XML”技术应用于非 XML 树结构。Colin 开发了 ILinqToTree<T>
适配器接口和一组扩展方法,允许以统一的方式对不同的树结构执行查询,无论是文件系统、数据库还是其他什么。这正是我为 WS-Enumeration 所需的,因此我在这里运用了 Colin 的方法。
背景
与 WS-Transfer 不同,WS-Enumeration 是一个有状态协议,用于基于过滤器枚举元素。枚举完成后,客户端会逐页拉取实例。
协议的工作方式如下:
- 客户端发送枚举请求。
- 基于枚举请求的参数,服务会构建枚举,创建上下文(枚举的标识符),并将其返回给客户端。
- 客户端发送一个拉取请求,其中包含“枚举上下文”和要返回的实例数。由于枚举上下文是必需的,因此拉取请求仅在枚举请求成功且枚举上下文过期之前有效。正是这种顺序,我们称 WS-Enumeration 为有状态的。
- 服务器在拉取响应中将数据返回给客户端。为了在 XML 中表示实例,我们使用了
IXmlSerializable
接口。 - 客户端会持续拉取数据,直到收到序列结束通知。
枚举
在处理枚举请求时,服务应根据提供的过滤器准备枚举。枚举请求可以包含 Filter 和 Dialect 属性。Filter 表达式可以是 XPath、正则表达式或其他。此 Filter 的行为应反映在 Dialect 属性中。如果服务收到具有不受支持的方言的枚举请求,则应向客户端发送一个故障。一旦枚举和上下文准备就绪,服务就会将“上下文”返回给客户端。
拉取 (Pull)
拉取请求应包含必需的“context”参数。context 就像服务中存储的枚举的唯一标识符。拉取操作请求给定枚举上下文的下一个 N 个对象实例,其中 N 在请求中提供。服务在响应中最多返回这些对象实例的 N 个 XML 表示。返回的每个对象都满足枚举请求中的过滤器。
GetStatus
“枚举上下文”具有有限的生命周期。GetStatus 请求用于获取指定上下文的过期时间。
Renew
此请求要求服务延长上下文的生命周期。此操作在长时间的拉取操作期间可能很有用。
Release
Release 请求启动上下文的删除。
概念与设计实现
理论上,该项目可以分为两个松耦合的部分:通信层和业务逻辑。
- 通信层 - WCF-Service。
- 业务逻辑 -(适配器 -> 工作流 -> LinqToTree)处理客户端请求的层。
适配器是通信层和业务逻辑之间的连接器。服务行为扩展允许通过配置文件配置服务行为。“type”属性的值决定了我们要使用的适配器的类型。
<configuration>
<system.serviceModel>
<diagnostics wmiProviderEnabled="true"/>
<services>
<service name="WSEnumeration.WSEnumerationService"
behaviorConfiguration="WxfServiceExtension">
<endpoint address="net.tcp://:11111/PublicStorage"
binding="netTcpBinding"
bindingConfiguration="Binding1"
contract="WSEnumeration.IWSEnumeration"/>
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="Binding1" transactionFlow="true"/>
</netTcpBinding>
</bindings>
<extensions>
<behaviorExtensions>
<add name="WSEnumerationAdapter"
type="WSEnumeration.ServiceAdapterBehaviorElement,
WSEnumeration, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null"/>
<add name="logger"
type="RKiss.Logger.LoggerBehaviorElement, Logger,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior name="WxfServiceExtension">
<WSEnumerationAdapter StoragePath="c:\"
ExpirationType="T|D|H|M"
Filtering="true"
FilterDialect="XPath"
type="WSEnumeration.Adapters.WFAdapter, WSEnumeration"
WorkflowTypeEnumerate=
"WSEnumerationWorkflow.FileSystem.WorkflowEnumerate,
WSEnumerationWorkflow"
WorkflowTypePull=
"WSEnumerationWorkflow.FileSystem.WorkflowPull,
WSEnumerationWorkflow"
WorkflowTypeRenew=
"WSEnumerationWorkflow.FileSystem.WorkflowRenew,
WSEnumerationWorkflow"
WorkflowTypeGetStatus=
"WSEnumerationWorkflow.FileSystem.WorkflowGetStatus,
WSEnumerationWorkflow"
WorkflowTypeRelease=
"WSEnumerationWorkflow.FileSystem.WorkflowRelease,
WSEnumerationWorkflow"/>
<logger enable="true" logAfterReceiveRequest="true"
logBeforeSendReply="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
以下是 WSEnumerationAdapter
元素属性的含义:
Attribute | 描述 |
StoragePath |
资源存储的路径。它可以是文件系统路径,也可以是数据库的连接字符串或其他。 |
ExpirationType |
过期时间可以是绝对时间或持续时间。此属性决定服务支持哪种过期类型。“T|D|H|M”表示:T-绝对时间,D-天为单位的持续时间,H-小时为单位的持续时间,M-分钟为单位的持续时间。 |
过滤 |
此属性的值反映了过滤器的支持情况。 |
FilterDialect |
此属性的值反映了服务能够理解的方言。例如,如果值为“XPath|Regex”,则表示服务可以理解 XPath 和 Regex 过滤器表达式。 |
类型 |
适配器类型 |
WorkflowTypeEnumerate |
Enumerate 请求的工作流类的类型。 |
WorkflowTypePull |
Pull 请求的工作流类的类型。 |
WorkflowTypeRenew |
Renew 请求的工作流类的类型。 |
WorkflowTypeGetStatus |
GetStatus 请求的工作流类的类型。 |
WorkflowTypeRelease |
Release 请求的工作流类的类型。 |
因此,通过配置文件,我们有可能配置我们的服务以处理文件系统、数据库或其他内容。当然,这仅在我们已经开发了相应的业务逻辑层的情况下。在此项目中,我开发了一个旨在处理文件系统的业务逻辑。
测试
为了演示 WS-enumeration 的工作方式,我创建了一个演示应用程序,允许用户浏览服务主机上的文件系统。
要设置服务主机资源目录,您必须在配置文件中设置“StoragePath”属性。现在,您可以启动服务了。服务主机与客户端的通信由 Roman Kiss 编写的日志记录器显示。客户端应用程序是一个单窗体,其中包含一个 DataGridView
,用于显示服务主机上某个目录的内容。
结论
就像语言模式(Singleton 等)或架构模式(MVC、MVVM 等)一样,WS-* 规范为我们提供了一种标准化面向服务应用程序(SOA)开发的方法。
目前,该项目尚处于开发阶段,不具备生产质量。尽管如此,它仍可用于研究或测试目的。
历史
- 2011/04/02 - 初始发布。