Azure 虚拟桥





5.00/5 (8投票s)
本文描述了托管在Windows Azure上的连接管道的消息中介器的设计和实现。
目录
特点
- 推送模型
- 使用 VETER 模式的消息中介器(管道)
- 业务集成器
- 一次性部署
- Xaml Bridge 定义存储在 Azure Blob Storage 中
- Web Role 和 Azure Storage 要求
- Windows Azure 服务总线消息传递(2011年11月)
- WF4 技术
- WCF4 技术
引言
Azure Virtual Bridge 代表了一个动态连接管道,用于通过 Microsoft Workflow Foundation (WF) 和 Windows Azure Platform 进行声明式的消息中介。特定连接的 Virtual Bridge 由 Bridge Definition 定义,存储在 Runtime Repository 中以便后续调用。
下图显示了其亮点
正如您所见,Virtual Bridge
是服务与其消费者之间的消息中介器,用于实现它们之间的集成,原因可能包括不同的协议、消息交换模式、数据契约、消息版本等。Virtual Bridge Mediator 在消息管道(bridge template)中具有预定义的模式,并且可以通过建模工具声明特定的业务集成。
Virtual Bridge
具有一个运行时服务,用于投影存储在存储容器中的选定 Bridge Definition。换句话说,通过部署 Virtual Bridge 包,我们可以根据业务需求动态管理端点之间的集成。请注意,Virtual Bridge
不是持久化的,它不是一个长时间运行的进程,而是一个内存中运行的消息中介器进程,其中消息代表一个状态。
Virtual Bridge 专注于集成过程和/或消息中介。其过程应以透明且可扩展的方式快速通过消息管道运行。
基本上,调用者如何消费 Virtual Bridge
,我们可以有许多不同的 bridge,例如 XML、SOAP、REST、X12、平面文件、SQL 等。本文仅讨论 SOAP bridge 具有 OneWay
和 TwoWay
消息交换模式,因此输入消息或请求/响应消息必须是 Soap 消息。
消息通过 bridge states 流经 Bridge 管道。基本上,Bridge 可以为每个方向定义 5 个 states。这些 states 的模式称为 VETER
,其中:
Validate
- 在此 state 中,消息被验证,例如,通过其 schema。Enrich
- 是一个用于修改消息的 state,例如,添加新类型等。Transform
- 在此 state 中,可以使用 XSLT 技术将消息转换为另一个 schema。Enrich
- 是一个消息可以再次被“处理”的 state。Route
- 在此 state 中,消息根据过滤条件分发到目标。
请注意,每个 VETER state 都是可选的,并且可以根据集成场景和业务需求被绕过(关闭)。
VETER 消息管道(bridge)的设计器可以硬编码并嵌入到宿主进程中。最近,Microsoft 发布了 Service Bus EAI 和 EDI Labs 的 CTP 版本更新,其中 VETER 模式已内置于 Visual Studio 2010 中,并扩展了 EDI 和 EAI 项目的服务总线模板。这是一个很棒的功能;我强烈建议评估此 CTP 版本。
以下图片是 OneWayBridge 示例项目截图
点击 Transform state 中的链接,将显示以下 Xml Mapper Editor
CTP 版本具有非常好的功能。然而,在此版本中,EAI & EDI Designer 无法重新托管,它与 Visual Studio 项目解决方案(包括程序集)紧密耦合。我希望 Microsoft 团队能够接受挑战,使 Software Bus EAI & EDI 的这项伟大功能能够重新托管,并将 VETER 模式作为 WF Designer 的自定义活动,包括一个 Mapper Editor 作为 EAI & EDI 业务的 WF 扩展。(请注意,此 CTP 版本构建在 WCF/WF 技术之上。)
好了,回到本文,它的实现并没有为“将消息管道‘装箱’”到 VETER 模式中提供特定的自定义活动,但是,WF Designer 允许基于 XAML Workflows 的“模式与实践”来构建此模式。换句话说,Bridge Definition 是一个序列(templates)的管道,可以根据业务需求进行定制。
下图显示了 Validate State 模板的示例,其中入站消息负载通过存储在 Azure Blob Storage 中的 schema 进行验证。
正如您所见,Sequence Validate
是一个非常轻量级的进程,具有来自 codeplex 项目 WF Azure Activity Pack CTP 1 的自定义活动和用于 XElement
的自定义扩展类。
XElement.Load(_inMessage.GetReaderAtBodyContents.ReadSubTree).MustBeValid(schema)
再举一个例子。下图显示了一个 Sequence,用于将管道消息 Enrich 并 Route 到 Service Bus Queue。
上述 state 使用自定义类扩展来将消息复制到特定的消息版本(在本例中必须是 Soap12WSAddressing10
),并使用我之前文章 Using Windows Azure Service Bus Messaging 中的自定义活动。第一个自定义活动将创建一个 brokered message,第二个活动会将此 brokered message 传递给 Service Bus Entity(queue)。
请注意,我在下载中包含了所有我提到的文章中的最新程序集,请参阅 Usage and Test 章节。
OneWay Bridge
这是一个基本 bridge,能够理解所有 states、集成过程和消息中介。下图显示了此 OneWay Bridge 模式。
消息以 FireAndForget
的方式推送到 Bridge,因此调用者不必等待其交付到目标目的地。入站的非类型化消息首先进入 Validate
state,在此根据 schema 进行验证,然后消息会被 Enrich(如果需要),并继续进入 Transform
state。基本上,此 state 代表 bridge 的业务核心,消息在此转换为目标 schema。下一个 state 再次用于 Enrich 消息,例如添加标头等。这是管道中的最后一个 state,消息可以在此 state 中修改。下一步是最终 state,即 Route
state,消息可以在此根据消息标头或负载的过滤条件路由到目标。
下图显示了 Route state 的示例,消息根据过滤器进行传递。
使用 Parallel
activity 内的 If
activity 进行过滤。条件是 brokered message 的 Label
属性,Target 是 Service Bus 的不同 Topic。
Bridge 中的 VETER
states 可以根据需要禁用(跳过)或激活其使用。下图显示了 ByPass
(或短路)Bridge 的示例,其中桥的入站消息会绕过管道中的所有 states 并传递到目标。
Virtual Bridge 可以与其他 bridge 链式连接,如图所示。
链式连接的 bridge 可以是 In-Process
,其中链式 bridge 位于父 bridge 的作用域内,也可以是 Remotely
调用的,就像另一个服务一样。正如我之前提到的,Virtual Bridge 是一个动态 Activity,因此 In-Process 链式 bridge 可以位于 ambient transaction 作用域内。
我最近的文章 Azure Service Bus Pusher 展示了如何将 brokered message 推送到 Target 目的地,如 Service Bus 和/或 http/https 服务。对于遗留 Target 或不同协议等情况,我们需要通过 Bridge 集成系统,消息可以在此进行中介。
下图显示了此场景的示例,其中 brokered message 被推送到 OneWay Virtual Bridge。Bridge 将负责 Azure Service Bus 和 Target Service 之间的集成。
这是一个很棒的集成。请注意,上述场景不需要为 bridge 提供服务(监听器)。另一个 OneWay Virtual Bridge 的绝佳示例如图所示,其中 Bridge 连接了两个不同的 Service Bus Namespaces,中介 brokered message 等。
这里还有一点想法,正如我之前提到的,Virtual Bridge VETER 由元数据驱动,bridge 定义存储在运行时存储库中以便在宿主服务进程中进行投影。对于其 Route
state,使用的是 WCF 范例,其中以声明式方式设置了通道堆栈,如传输、绑定、契约等。这种抽象允许 VETER Bridge 的虚拟化,并将特定的通信层封装在自定义通道中。通过在 Bridge Definition 中进行配置,可以选择不同的 Target,如 Service Bus、SQL、文件系统等,而无需修改 VETER 模式。换句话说,我们可以利用 WCF 堆栈的可扩展性,而不是构建自定义适配器/活动。这个设计和架构的一个好例子是 Workflow Custom Channel,它是这个 Virtual Bridge 的核心 - 稍后或在我的文章 RoutingService on Azure 和 WorkflowChannel for Routing Service 中可以找到更多详细信息。
TwoWay Bridge
TwoWay Bridge
是另一种用于消费 Bridge Definition 的消息交换模式。在这种通信中,消费者向 Bridge 发送请求消息,并以同步或异步方式等待其响应。基本上,TwoWay Bridge
是在一个 Bridge Definition 中组合了两个 OneWay Bridges,其中第二个 Bridge 具有一个特殊的 Route state 用于将 Reply 消息发送回调用者。下图显示了这个模型。
TwoWay Bridge
允许在 Bridge 管道中中介请求和响应消息。这两种模式都是 VETER
模式,其 states 基于集成和业务需求。
下图显示了一个 TwoWay Bridge
,其中 Response 是 VOID
。换句话说,Response Bridge 没有需要中介的内容,消费者希望等待调用完成或收到 fault message。
在上面的示例中,Request Mediator(管道)中的消息是根据业务集成过程进行处理的,Route state 将根据过滤规则将消息分派到服务,在此 state 之后,void response 会通过空的 Response pipeline 进行回复。请注意,Response Route state 始终是用于分派 Reply 消息的 state,因此我们可以说,TwoWay Bridge 对于“匿名回复地址”(如返回给调用者)具有强制的 Route-Reply state 用于 Response pipeline。
TwoWay Bridge
的 Bridge definition(管道)可以根据消息中介需求进行简化。我可以在下图中进行解释,其中我们有一个 TwoWay Bridge,在任何管道 state 中都没有外部调用,换句话说,Bridge Definition 使用本地或嵌入的中介原语和消息 state 来处理此管道。
基本上,在这种场景下,我们可以跨 Bridge 共享这些 Bridge Definitions(templates)。例如,用于将文档转换为 EDI X12、EDIFACT、Flat File、CSV、图像和其他许多格式的 Bridge Definition。
调用者 Bridge 在 Transform
state 中可以完全透明地调用这个“小型 Bridge”,就像调用常规服务一样,请参见下图。
正如您所见,“小型 Bridge”代表了一个典型的消息中介原语,用于将输入消息转换为不同格式的输出消息。调用此 Bridge 可以是 In-Process 或跨进程边界的 Remotely。
Untyped Message
Bridge 的入站消息是 untyped message,因此 Bridge Definition 负责验证其内容并将其反序列化为对象。消息在管道中使用 XML 技术进行中介。我建议阅读我的文章 WF4 Custom activities for message mediation,其中详细描述了 xaml workflow 中的此技术。
下图显示了此技术的一个示例,用于动态自定义 https 绑定并带有 Basic Authorization。第一个自定义活动是一个通用的自定义 xslt 活动,用于运行时转换绑定对象的 xslt 资源。下一个活动(如 BindingScope)将使用此对象来发送 Activity。
Bridge Definition 是一个 xaml Dynamic Activity,带有 VETER Template。基本上,Bridge 的最小声明显示在以下示例中,其中通过将消息 _inMessage = _outMessage
来声明一个“loopback” Bridge。
请注意,Bridge Definition 不包含任何用于空闲工作流状态的活动,如 Receiver、Timer 等。Bridge 用于短暂的内存运行工作流(动态活动)。
Virtual Bridge 基于 Contract First 模型,其中 contracts、schemas、resources、artifacts 等在 Design Time 存储在 Repository 中。Virtual Bridge 为所有 Bridge Definitions 提供了一个虚拟端点。
下图显示了一个调用 HelloBridge
definition 的示例。
正如您所见。第二个寻址允许指定存储 HelloBridge
Bridge Definition 的 Repository 名称。请注意,此 url 查询会传递到 Bridge Arguments 以便在 VETER 管道中使用。
有关由元数据驱动的可管理服务的更多概念性详细信息,请参阅我的文章 Contract Model for Manageable Services 和 Manageable Services。
从概念上讲,存在一个逻辑上的中央 Repository 用于 Contract(Model)First 资源,客户端/消费者以及工具都可以查询以获取元数据(mex、wsdl、xsd 等)用于建模、创建代理等。Contract Model 可以存储在 Windows Azure Platform 中,包括一个用于资源查询的 web role 服务。请注意,此模型不包含在本篇文章中,我提到它的原因是想给您一个关于元数据驱动服务的完整图景和架构风格。
我推荐查看 Microsoft 的 Announcing the Refresh of Service Bus EAI & EDI Labs,我希望本文能帮助您使用 Microsoft 技术优势来理解系统之间的集成和消息中介。
好的,让我们继续 Virtual Bridge 的概念和设计。我假设您对 Windows Azure Platform 和 WCF/WF 技术有实际的了解。
概念与设计
Azure Virtual Bridge
的概念基于 WCF Custom WorkflowChannel
。我建议阅读我的文章 WorkflowChannel for Routing Service 和 RoutingService on Azure,其中我详细描述了如何构建和使用 WorkflowChannel
。我特意为 Windows Azure Platform 重建了这个自定义通道,并将其连接到 Azure 资源。在本节中,我将重点介绍这些功能。
下图显示了 Azure 上 VirtualBridge 的概念:
正如您所见,这个概念非常简单,有一个常规的 WCF Routing Service、Azure Blob Storage 和一个“魔法组件”,如 WorkflowChannel
。这个自定义通道是为特定目的构建的(仅支持 IOutputChannel
和 IRequestChannel
),例如在由 Web Role 托管的 Routing Service 下动态投影 Bridge Definition。
Consumer 的入站消息由 Routing Service 接收,并根据消息交换模式(OneWay 或 Request/Reply)转发到出站路由通道,如 WorkflowChannel
。此场景的配置在 web.config 文件中进行。
下图显示了此配置文件的一部分。
VirtualBridge 以 REST 风格寻址,其中 url 地址的查询部分专门用于 bridge definition,即元数据是什么以及在哪里。下图显示了 bridge definition HelloBridge
的示例。
WorkflowChannel
可以识别入站消息的完整条目地址,这对于其加载器逻辑动态从 Azure Storage 加载所需的 bridge definition 至关重要。存储容器的名称可以在配置文件中配置为默认容器,或者可以添加到 url 地址的查询部分,例如:xaml=HelloBridge&repository=demo
Virtual Bridge 的物理 url 地址可以根据业务需求进行重写。对于 Windows Azure,这非常简单直接,因为 IIS 模块默认安装。下图显示了此功能的一些示例。
第一个示例的 web.config 文件中的 rewrite
部分显示在以下屏幕截图中。
我喜欢这个功能,它允许将服务的物理地址路径映射到逻辑地址路径。
Routing Service 配置的其他有趣部分是 bindings
。下图显示了这部分。
正如您所见,有两个绑定,第一个是出站自定义 WorkflowChannel,另一个是基于 Basic client credentials(使用用户名和密码)的入站安全通道的自定义绑定。
下一节是 behaviors
。
在 behaviors 部分,我们需要配置路由、serviceCredentials、在 ServiceBus Topic 上发布未处理的错误以及工作流跟踪。第一个,如路由扩展,是 Routing Service 的强制元素;其他元素是可选的,取决于我们是否需要使用安全传输、错误处理和跟踪。ClientCredentials 在 WorkflowChannel 中授权,并且对每个 Bridge Definition 都是独立的。
请注意,sqlTracking
扩展不包含在本篇文章中,但实现自定义跟踪和日志记录并不困难。另一方面,我在本解决方案中包含了一个 Service Bus Publisher,可用于在 Topic 上进行自定义跟踪。
正如您所见,路由服务配置文件是我们“烹饪甜点”的地方。Virtual Bridge 的所有功能都基于可插拔的组件,因此可以根据业务需求轻松替换。
另一个配置。Routing Service 由 Web Role 托管,因此所有重要配置都封装在 web role 设置中,以便进行“动态”更改。
下图显示了这些设置。
Bridge Definition
Bridge Definition (BD) 代表了一个 xaml workflow 动态活动,用于使用 VETER 模式进行消息中介。从架构角度来看,BD 是用于以声明式方式表示集成过程的元数据。在设计时,我们使用重新托管的 workflow designer 根据业务需求创建此元数据,并将其存储在运行时存储库(如 Azure Blob Storage)中。一旦此资源存储在此存储库中,WorkflowChannel
就可以将其获取并投影到 Router Service 中。
下图显示了这个场景。
WorkflowChannel
内置了一个用于 IOutputChannel 和 IRequestChannel 的“发送器”,用于处理加载 Bridge Definition、创建其实例、传递参数、设置等的所有步骤,然后调用此动态活动。Virtual Bridge 是一个可扩展的、多租户的可管理服务,托管在具有多个实例的 Web Role 中。此功能允许以一次性部署的方式弹性地运行多个 bridge。在运行时,随时可以修改 Bridge Definition、添加新 Definition、移除 Definition、切换到另一个版本、回滚版本、重定向 Repository 或 Blob 等。
请注意,本文(公开版本)不支持缓存 Blob Storage 中的 Bridge Definition 及其 clr 类型。实现缓存无效化特定 Bridge Definition 在 Web Role 实例之间并不困难。我在最近的文章 Azure Service Bus Pusher 中实现的解决方案可以作为初始功能的宝贵资源。
寻址 Bridge Definition
调用特定的 Bridge Definition 由入站消息地址驱动,其中 url 查询包含位于 web role 设置中配置的默认 Blob Container 中的 Bridge Definition 名称。通过在消息地址中添加其他查询参数,如 repository
和 settings
,消费者可以选择同一存储账户中的其他容器/blob/元数据。
以下是寻址(查询)Bridge Definition 的示例。
- xaml=HelloCloud
- xaml=HelloCloud&repository=Demo
- xaml=HelloCloud&repository=Development
- xaml=HelloCloud&settings=bridges/Settings/HelloCloud_Demo
- xaml=HelloCloud&repository=Development&settings=bridges/Settings/HelloCloud_Dev
请注意,为了接受地址查询中的 settings
参数,默认(主)Bridge Definition 需要通过插入元数据参数 _metadataLocation=user
来启用此功能,稍后会提供更多详细信息。
管理 Bridge Definition 地址路径的另一种能力是将 url 查询中定义的默认(主)地址路径(请参阅以上示例)重定向到同一存储账户内的任何容器。下图显示了这种情况。
默认(主)容器通过 web role 设置配置,或者直接在 url 查询中配置。WorkflowChannel
内置了检查 blob 内容类型的功能。对于 text/plain
且 url 地址 schema 为 https
的情况,它将从此地址下载 bridge definition 资源。上图显示了 HelloCloud2 的示例,其中其 bridge definition 的正文是从 Demo
容器中提取的,特别是名为 HelloCloud_version_1.0.0.0
的 blob。
这太棒了。此机制允许根据需要重定向 bridge definition,例如新版本、回滚版本、临时版本等。本文版本不包含 Virtual Bridge Management Portal(web role)来管理 Virtual Bridge、其 definitions、元数据、设置、部署等。我希望您能获得构建一个适合您需求的 portal 的想法。
再补充一点,正如您所知,每个特定的 blob 都有自己的用户定义元数据迷你块(header),作为 name-value 对的集合(详见下一节)。WorkflowChannel 有一个选项可以动态选择哪些元数据将与 blob 资源一起加载。此选项通过在用户定义元数据中插入特殊属性(_metadataLocation
)来激活和处理 - 稍后会提供更多详细信息。基本上,它们能够使用本地、远程、用户或特定的元数据 blob。
消费 Bridge Definition
从抽象的角度来看,Bridge Definition 可以通过消息交换模式(MEP)进行消费。WorkflowChannel 只支持两种 MEPs,如 OneWay 和 TwoWay(Request/Reply)消息交换模式。
下图显示了这种抽象,其中 _inMessage
是入站 Routing Service 消息,对于第二种 MEP,使用 _outMessage
将其回复给调用者。
WorkflowChannel 负责如何根据入站消息使用此 MEP。换句话说,Bridge Definition 可能包含此 _outMessage
,但在 OneWay MEP 的情况下不会使用它。
请注意,Routing Service 的入站/出站消息的默认设置是 Soap11。
Bridge Definition 的参数
WorkfowChannel
和 Bridge Definition 之间的连接是通过 xaml Dynamic Activity 参数实现的。这是一个非常重要的点,也是设计时和 VETER templates 的必需元素。每个 Bridge Definition 都必须具有以下参数:
我们可以将这些参数称为 Bridge Definition Arguments
。WorfklowChannel
会检查这些参数的名称和类型,如果匹配不上,则会抛出 Exception,并附带缺少特定参数的原因消息。
我知道,您可能认出了 _inMessage
和 _outMessage
这两个参数,如上所述,但是 _metadata
是什么,为什么我们会在 Bridge Definition 中需要它?
好了,这个参数代表了特定 Bridge Definition 的设置;它是一个 name-value 对的集合,就像配置文件设置部分一样。基本上,这是 blob 元数据实体的一个副本,我们可以称之为 Bridge Definition Metadata。此外,您稍后会看到,这是动态管理特定 Bridge Definition 和 WorkflowChannel 运行时配置的一个好地方。
blob 元数据具有以下特性和限制:
- 名称不区分大小写。请注意,元数据名称会保留创建时的原始大小写,但在设置或读取时是不区分大小写的。如果为资源提交了两个或多个同名的元数据标头,Blob 服务将返回状态代码 400(Bad Request)。
- 元数据的总大小,包括名称和值,不得超过 8 KB。
- 元数据名称/值对是有效的 HTTP 标头,因此它们遵循 HTTP 标头的所有限制。
- 可以之间检索或设置元数据,而无需返回或修改 blob 资源(正文)的内容。
请注意,Bridge Definition Metadata 也可以在运行时通过自定义活动进行修改、添加等,就像 Azure Storage 中的另一个资源一样。
下图显示了 Bridge Definition 的“数据 schema”。
希望您现在能看到 blob 元数据在 Bridge Definition 中的位置。它是特定 Bridge Definition 的本地设置,可以由自定义门户、bridges 等进行管理。让我们更详细地讨论一下这个元数据。
Bridge Definition Metadata
Bridge Definition Metadata 代表 Azure Blob Storage 中特定 Bridge Definition 的设置。这个专用的 name/value 字符串对的 blob 实体允许我们将 Bridge Definition 的依赖项解耦到本地小存储(最大 8k),并制作一个更通用的 VETER Bridge。WorkflowChannel 可以在不下载完整 blob 内容的情况下读取此元数据,因此这个属性集合可以共享以动态定制自定义通道。blob 元数据中属性的值是文本。
下图显示了 Bridge Definition Metadata(如 blob 元数据)的示例。
正如您所见,有几个突出显示的名称。这些是 WorkflowChannel 识别的特殊属性,用于一些非常酷的功能,详见下文。
Bridge Definition Metadata 属性的保留名称
_username
,这是客户端授权的强制属性。_password
,这是客户端授权的强制属性。_trackingProfileName
,用于跟踪级别的可选属性。_metadataLocation
,用于选择元数据 blob 的可选属性(见前文描述),有效值为:local
、remote,user
或当前存储账户内的任何 blob 的 url 地址。_urlQuery
,这是 bridge 地址 url 查询参数的隐藏属性,格式为 name/value 对。
_username
和 _password
用于访问特定 Bridge Definition 的客户端 Basic Authorization。要关闭此功能(接受任何 u/p),请将两者都设置为字符 '*'。
下一个属性,如 _trackingProfileName
,用于 bridge 运行时跟踪(如果我们有的话)。此功能允许动态地或通过自定义门户进行管理地更改特定 bridge 的跟踪级别。
_urlQuery
属性允许我们将入站地址 url 查询的集合获取到 Bridge 中,作为额外的业务参数。
最后一个属性,如 _metadataLocation
,赋予了 Virtual Bridge 的强大功能。这是 WorkflowChannel 用于管理 blob 元数据源的属性。如果此属性不存在或其值为 local
,WorfklowChannel 将使用默认(主)blob 存储和指定的 blob。如果使用远程(间接)Bridge Definition,此值必须设置为 remote
。
下一个选项是 user
,如果用户想为 Bridge Definition 选择自己的设置(每次调用),可以通过地址 url 查询部分实现,例如:settings=bridges/Settings/HelloCloud_Dev
。
最后,当我们想要拥有多个设置时,例如,基于环境范围(如开发、暂存、QA、演示、生产等),我们可以将此属性的值显式设置为 blob 资源的 url 地址。此地址也适用于相对寻址,例如:~/bridge/Settings/HelloCloud_Dev
其中 ~ 表示 web role 设置配置的默认 blob 存储。
下图显示了映射 Bridge Definition 的示例。
入站消息(xaml=HelloCloud2
)将加载默认(主)Bridge Definition。WorkflowChannel
将检查其内容,并根据内容将加载器重定向到 Bridge Definition HelloCloud_version_1.0.0.0
。现在,WorkflowChannel 需要加载 Bridge Definition Metadata。这里再次有一个选项定义在 _metadataLocation
属性中,在本例中是完整的 url 地址,因此其加载器将从 HelloCloud_Demo
blob 中获取它。
这是一项很棒的功能,允许我们将物理 Bridge Definition 映射到逻辑 Bridge Definition。请注意,此映射可以通过自定义门户手动完成,或通过其他 bridges 以编程方式完成。
现在,让我们继续讨论另一项很酷的功能,即跨多个 Bridge Definitions 的 Enterprise Variables。
Enterprise Variables
Enterprise Variable 是一个可以在多个 Bridge Definitions、客户端等之间共享的变量。这些变量存储在 Azure Table Storage 中,可以通过变量名(PartitionKey
)和环境范围(如 DEV、QA 等)(RowKey
)进行查询。变量实体非常简单,如以下代码片段所示。
public class VariableEntity : TableServiceEntity { public string Value { get; set; } public string ApplicationScope { get; set; } public string Description { get; set; } }
以及它们在 Azure Table 中的存储。
Enterprise Variables 是为 Bridge Definition 设计的,因此它们的实现与 WorkflowChannel 分开,位于其自己的程序集中,名为 EnterpriseVariables
。可以选择在 Bridge Definition 中使用它。使用 enterprise variable 非常简单,可以使用内置的静态类 RuntimeRepository.Variables
。此类有 4 个静态方法,如下所示。
public static string GetValue(string name, string scope = "*", string format = null, params object[] args) public static string GetValueOrDefault(string name, string defaultValue = "", string scope = "*") public static VariableEntity Get(string name, string scope = "*", bool bThrowNotExist = true, string format = null, params object[] args) public static IEnumerable<VariableEntity> GetAll(string filter = "*")
Enterprise Variables 的用法示例。
- RuntimeRepository.Variables.GetValue("Hello Roman") // 获取变量 'Hello Roman' 的值,如果不存在则抛出异常。
- RuntimeRepository.Variables.GetValue("Hello " + "Roman") // 获取变量 'Hello Roman' 的值,如果不存在则抛出异常。
- RuntimeRepository.Variables.GetValue(
localVariable1
) // 获取存储在局部变量localVariable1
中的变量名,如果不存在则抛出异常。 - RuntimeRepository.Variables.GetValueOrDefault("Hello Roman") // 获取变量 'Hello Roman' 的值,如果不存在则返回空字符串。
- RuntimeRepository.Variables.GetValueOrDefault("Hello Roman", "Hello Cloud") // 获取变量 'Hello Roman' 的值,如果不存在则返回 'Hello Cloud'。
- RuntimeRepository.Variables.GetValue("Hello Roman", "*", "Missing variable '{0}''", "Hello Roman") // 获取变量 'Hello Roman' 的值,如果不存在则抛出带有消息“Missing variable 'Hello Roman'”的异常。
- RuntimeRepository.Variables.Get("Hello Roman", "DEV") // 获取
DEV
作用域中名为 'Hello Roman' 的变量实体,如果不存在则抛出异常。 - RuntimeRepository.Variables.GetAll("RowKey eq 'DEV'") // 获取
DEV
作用域的所有实体 - RuntimeRepository.Variables.GetAll("PartitionKey eq 'Hello Roman') // 获取名称为 'Hello Roman' 的所有实体
Bridge Definition 可以将一些变量封装到 Bridge Definition Metadata 中进行管理。我们可以从集合 _metadata 中获取它们的值。以下示例显示了此用法。
- RuntimeRepository.Variables.GetValue(_metadata.Item("text")) // 获取
_metadata
属性“text”中的变量名,如果不存在则抛出异常。 - RuntimeRepository.Variables.GetValue(_metadata.Item(
localVariable1
)) // 获取_metadata
属性localVariable1
中的变量名,如果不存在则抛出异常。
这太棒了,通过使用 Bridge Definition Metadata 属性,我们可以将这些变量管理在 Bridge Definition 之外。此属性的值代表 Enterprise Variable 的物理名称。如果我们想将变量的逻辑名称映射到物理名称,我们可以使用 enterprise variable 的别名。前缀字符 '@' 将表示此名称是别名。
下图显示了此映射。
Bridge Definition 调用静态方法以通过 _metadata 属性“text
”获取 enterprise variable 的值,即 RuntimeRepository.Variables.GetValue(_metadata.Item("
。在别名的情况下,方法将根据特定作用域从 Table Storage 中获取值。这是一个非常强大的功能,允许我们重新映射、集中化和共享 Bridges 和 Composite Applications 的变量。text
"))
请注意,这里描述的 Enterprise Variables 概念具有简单的设计和实现,对于更复杂的设计,请参阅我的文章 Enterprise Variables for WF4。
Assemblies Blob Storage
WorkflowChannel 内置了一个 AssemblyResolve 的处理程序。此处理程序在绑定扩展期间设置。其实现显示在以下代码片段中。
public class WorkflowTransportElement : BindingElementExtensionElement { public WorkflowTransportElement() { System.AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs args) { string assemblyName = args.Name.Split(',')[0].Trim(); try { Trace.TraceInformation("ResolveInternalAssembly: Resolving = '{0}'", args.Name); string container = RuntimeRepository.GetConfigString(RuntimeRepository.VirtualBridgesStorageContainerNameForAssemblies); if (string.IsNullOrEmpty(container) == false) { Resource resource = RuntimeRepository.GetResource(RuntimeRepository.VirtualBridgesStorageSettingName, container, assemblyName, false); if (resource.Body != null) return System.Reflection.Assembly.Load(resource.Body); } } catch (Exception ex) { Trace.TraceInformation("ResolveInternalAssembly name = '{0}' failed. Error = {1}", assemblyName, ex.Message); } return null; }; } // ... }
逻辑很简单;AppDomain.CurrentDomain
会触发一个事件,表示找不到 Bridge Definition 中声明的 clr 类型。上述处理程序负责从 Azure Blob Storage 加载请求的程序集并将其返回,如果请求的程序集无法识别则返回 null。
Blob Container 的名称在 web role 设置中指定。
在 Topic 上发布错误
WCF Custom WorkflowChannel 未处理的错误可以发布到 Service Bus Topic。这是 web.config 文件中 WorkflowChannel 的一个选项,并且实现在单独的程序集 Notifications
中。以下代码片段显示了此处理程序的实现。
public class EndpointPublishErrorHandler : IErrorHandler { public void ProvideFault(Exception error, MessageVersion version, ref Message fault) { } public bool HandleError(Exception error) { Trace.TraceError("HandleError: {0}", (error.InnerException == null ? error.Message : error.InnerException.Message).Replace("\n", "\n ")); MessageFault fault = MessageFault.CreateFault(new FaultCode("VirtualBridge"), error.Message); Publisher.Publish(Severity.Error, fault); return true; } }
正如您所见,逻辑非常简单,使用静态方法实现此功能。请查看 Notification.cs
文件中的源代码,其中实现了用于将 brokered message 发送到 Azure Service Bus Topic 的 wcf 客户端。Publisher 可以在 web role 设置中配置。
好了,到了展示时间了。让我们在 Azure 上演示 Virtual Bridge。我假设您对 Windows Azure Platform 有实际的了解。
用法与测试
首先,以下是先决条件:
- Visual Studio 2010 SP1
- Windows Azure SDK v1.6 (2011年11月)
- Windows Azure Platform 账户
- Http/s Internet 连接
- 下载本文的软件包
- Azure 存储浏览器
- Service Bus Explorer (可选)
- Azure Service Bus Tester (可选)
- Windows Azure Platform、WCF 和 WF 的知识和经验
AzureVirtualBridge
解决方案需要构建和部署 Azure 应用程序、Blob/Table Storage 以及使用 Azure Service Bus Messaging(包括上述第三方工具)的知识和经验。因此,我假设您对 Windows Azure Platform 有实际的了解。
本文解决方案包含 6 个项目,如图所示。基本上有 4 个主要文件夹:AzureVirtualBridge、VirtualBridgeWebRole、Lib 和 Test。Test 文件夹仅用于测试目的,不属于 Azure 包。
Lib
文件夹包含此解决方案的核心,例如 WorkflowChannel
项目,其中实现了自定义 wcf 通道用于 Bridge Definition。其他程序集是可选的,可以通过配置文件插入到 WorfklowChannel
中,如前所述。在编译解决方案之前,请更改您的账户的 web role 设置。容器的默认名称,其中存储 Bridge Definitions 是 bridges
。如果您的 Storage account 中出现命名冲突,请更改它,例如 bridge2
。
还有一点,VirtualBridge Service 有一个安全端点,因此请添加您的证书或临时将其配置为 http 绑定。
现在是编译上述解决方案的时候了。希望您能毫无错误地完成。
我知道,这是个困难的部分,但让我们一步一步来。基本上,我将这些步骤分为 4 个主要组:准备 Azure Storage、准备 Service Bus(可选步骤)、在 Emulator 和 Azure Storage 组合中运行,最后一步是成功部署 VirtualBridge 包到 Azure。
步骤 A:准备 Azure Storage 的测试数据
这是第一步,我们需要在 Azure Storage 中创建容器。对于这一步,我们可以使用任何第三方工具,我推荐免费工具 Azure Storage Explorer,它可以进行修改(扩展)以增加附加功能,例如启动工作流设计器。
以下 AzureStorage
解决方案文件夹包含要上传到 Azure 指定容器的数据。首先,创建三个 Blob Storage 容器:assemblies
、bridges
和 schemas
。之后,我们需要一个表。请创建一个名为 Variables
的表。容器和表位于同一个存储账户中,但也可以根据设置位于不同的账户中。
太好了,现在我们需要上传文件。
下图显示了我们用于测试的附加程序集。请上传 3rdParty 文件夹中的这些程序集,并移除其文件扩展名。您可以上传多个文件,也可以一个接一个地上传。
接下来上传此解决方案中 3rdParty 文件夹中的所有文件。上传完成后,请将其 Content Type
更改为 application/xaml+xm
。
对于 schemas
等资源,我分配了一个单独的 blob 容器。请上传此资源并更改其 Content Type。
对于 Variables,我们不需要进行任何手动调整,只需将文件 Variables.xml
上传到 Variables 容器。
Azure Storage 操作就完成了。
下一步与 Service Bus 上的 Notification 相关。您可以跳过此步骤,稍后再添加。在这种情况下,请在 web role 设置中禁用此功能。
< Setting name="RKiss.Publisher.ServiceBusPublisherEnabled" value="false" />
步骤 B:在 Service Bus 上创建 Topic 和 Subscription(可选)
在此步骤中,我们需要创建一个名为 'Bridges
' 的 topic 和一个 subscription,例如 Notifications,过滤条件为 publisherKey='911'
。请使用第三方工具 Service Bus Explorer 在您的 Service Bus namespace 中创建这些实体。请注意,web role 设置必须与这些实体匹配。
一旦我们在 Service Bus 上有了 subscription,我们就可以订阅一个虚拟 subscriber 来接收 Topic 'Bridges' 上的感兴趣事件。下图显示了另一个有用的工具,如 Azure Service Bus Tester。
正如您所见,从 VirtualBridge 收到了一条消息。具体来说,这是一个通知,表示消息已发送到不存在的 Bridge Definition。
步骤 C:Emulator + Azure Storage
在此步骤中,我假设所有先前的步骤都已成功完成。让我们做一个非常简单的测试,比如 Hello Cloud
。请注意,这次我们将运行 Windows Azure Emulator,但 Storage 在 Azure 上。使用 Emulator 允许我们调试 WorkflowChannel 和其他有趣的部分。
解决方案中包含一个客户端测试程序,用于发送单向或请求/回复 MEP 的消息。
步骤 C1 - 调用 HelloCloud Bridge
这是您对 VirtualBridge 的第一个测试,使用 HelloCloud Bridge Definition。下图显示了其定义。
您可以看到,这是一个非常直接的 bridge(mediator),用于生成带有 text
主体的回复消息。text 主体是一个局部变量,从 Bridge Definition Metadata 初始化。
在我们运行此测试之前,我们需要设置 Bridge Definition Metadata(例如 blob 的元数据用户块),内容如下:
请注意,带有下划线前缀的属性是 WorkflowChannel 的强制要求。在本例中,bridge 必须使用客户端凭据(Roman/12345
)进行授权。
好了,让我们做一个测试。请从 Test 文件夹启动 BridgeClient Tester
。Tester 具有预定义的默认设置,因此您只需按下 Invoke
按钮即可。
但是等等,当然我们需要运行 Emulator,然后按下 Invoke 按钮。下图显示了这个测试的结果 - 调用 bridge(mediator)Hello Cloud
。
您可以在这里停留并尝试客户端凭据、调试 WorkflowChannel、更改消息版本、text
的值等。
在下一步中,我将向您展示如何将局部属性 text 移动到 Enterprise Variables 中。
步骤 C2 - 使用 Enterprise Variable
在 Bridge Definition 中使用 Enterprise Variables 需要进行一些更改。WF4 不支持变量解析器,而变量解析器对于插入源来解析特定变量的值(超出范围)非常有用。即将发布的 WF4.5 版本也不包含此功能,因此我们需要使用一些变通方法,例如使用我之前提到的静态方法。
无论如何,我们需要使用以下表达式初始化变量 text:
RuntimeRepository.Variables.GetValue(_metadata.Item("text"), "QA")
此表达式的意思是:获取元数据中位于 QA 作用域的 text 属性的值。
作为第二项也是最后一项更改,我们需要在 Bridge Definition Metadata 中进行以下更改:
通过在 text 属性的值前加上前缀 '@',我们实际上是将存储重定向到存储 Enterprise variables 的 Table Storage。web role 设置中的默认设置显示此表存储的名称为 Variables
。
我在 V2 子目录中包含了此版本的 Bridge Definition,因此调用此 bridge 的地址如下:
https://127.0.0.1:444/VirtualBridge/TwoWay?xaml=V2/HelloCloud
请将此新地址复制到 Tester 中,然后按 Invoke
按钮。您应该看到 QA 作用域中 Variables 表中的文本,例如 'Hello Cloud from QA'
。
步骤 C3 - 调用 Test.ZipCode Bridge
此测试演示了 TwoWay bridge,其中调用 VETER 管道的 Transform state 中的远程中介器。天气公共 Web 服务(http://wsf.cdyne.com/WeatherWS/Weather.asmx)用作远程中介器的示例。为了创建此 bridge definition,使用了我文章 WF4 Custom activities for message mediation 中的自定义活动 CreateMessage
(最新的程序集包含在解决方案中的 3rdParty 文件夹中)。
此示例的 Bridge Definition 如下所示。
上述模型很简单,第一个自定义活动 CreateMessage 根据其 wsdl 合约(Contract First 方法)创建一个用于远程 Web 服务的请求消息,第二个活动为 bridge definition 的消费者创建一个回复消息。有关自定义活动的更多详细信息,请参阅文章 WF4 Custom activities for message mediation。
在我们运行测试之前,我们需要创建 Bridge Definition Metadata。下图显示了这些属性。
好的,现在我们可以进行一些测试了。请选择此 Test.ZipCode
bridge 的地址,然后按 Invoke 按钮。您应该得到与以下屏幕截图相同的结果。
太好了,现在我们想在 VETER
模式中添加一个用于验证输入消息的 state。下一步将展示如何完成此任务。
步骤 C4 - 调用带有消息验证的 Test.ZipCode Bridge
此测试标记为 Test.ZipCode
Bridge Definition 的版本 V2
,其中使用 Blob Storage 中存储的 schema 验证入站消息。我将向您展示 VirtualBridge 解决方案的更多功能,但首先我们需要准备并插入一个重新托管的 Workflow Designer 到 Bridge Definition 中。
- 扩展 Azure Storage Explorer 以实现所选 Blob 资源的
View With
和Edit
功能,如图所示。我在我之前写的文章 RoutingService on Azure 中详细描述了此扩展。此扩展允许我们启动WorkflowDesigner
来建模 Bridge Definition。当然,它也可以与任何 designer 相关联,例如 Visual Studio。
请注意,WorkflowDesigner 程序包含在 3rdParty 文件夹中。它是我在之前文章 WF4 Custom activities for message mediation 中描述的解决方案的最新更新。
如果一切顺利,您应该在 WorkflowDesigner 中看到 V2/Test.ZipCode
Bridge Definition,如下面的屏幕截图所示。
太好了。我们还需要为 Bridge Definition Metadata 进行一项手动步骤。请在此 blob 元数据中插入以下属性,并使用您的存储账户:
现在回到我们的测试,我想演示 VETER 模式中的 Validate State
。此 state 在以下 sequence 作用域中声明:
正如您所见,这是一个非常简单的 sequence。第一个活动将从 Blob Storage 获取资源(schema)。这是来自 WF Azure Activity Pack CTP 1
的自定义活动,我在 ConfigurationName
属性中做了一些小的更改。更新后的程序集包含在 3rdParty 文件夹中。
一旦我们有了 Blob Storage 中的 schema 资源的正文,我们就可以调用 XElement
扩展方法 Validate。此方法的实现可以在 EnterpriseVariables 项目的 ClassExtensions.cs 文件中找到。
XElement.Load(_inMessage.GetReaderAtBodyContents.ReadSubTree).Validate(bodySchemaResource)
就是这样。现在我们可以调用 V2/Test.ZipCode Bridge Definition 了。请复制并粘贴此地址到 Tester,然后按 Invoke 按钮。
https://127.0.0.1:444/VirtualBridge/TwoWay?xaml=V2/Test.ZipCode
我希望您能看到此 bridge 返回的正确回复消息。您可以在 Tester 中更改请求消息,例如,修改 ZIP 元素并按 Invoke 按钮,查看 bridge 的响应。
这个测试就到此为止。
让我们做一个更高级的测试。用例是将“遗留消息”发送到 Service Bus Topic。
步骤 C5 - 将“遗留消息”发布到 Service Bus Topic
此测试将演示 VETER 模式,其中 bridge 管道中的消息会被验证、转换、enrich 并路由到 Service Bus Topic。Bridge Definition 的名称是 Publisher
。
下图是 Workflow Designer 的屏幕截图。
Validate
state 已在之前的测试中描述。下一个 state 是 Transform
,其中使用了来自文章 WF4 Custom activities for message mediation
的自定义活动。Transform
activity 中的 mediator 是一个非常简单的 xslt 资源,用于复制元素,它嵌入在 Bridge Definition 中。另一种选择是将此 xslt 资源存储在 Blob Storage 中,并像我在上一步中描述的那样检索 schema 资源。
下一个 state 是 Enrich
state,演示了如何为 Service Bus 创建 brokered message。最后一个 state 是 Route
state,其中 brokered message 被发送到 Topic
(在此示例中为 bridges
)。
bridge 是根据 Bridge Definition Metadata 属性配置的。请使用您的账户为这个 blob 创建这些属性。
一旦有了上述设置,我们就可以运行测试了。请选择以下地址并按 Invoke 按钮。您应该看到回复消息“Done”。
来自 topic bridges 的 brokered message 可以由以下 Tester 中的虚拟 subscriber 接收。
这个测试就到此为止。
合并 web role 与 worker role
在我之前的文章 Azure Service Bus Pusher 中,我介绍了一个 worker role,用于将消息从 Service Bus 推送到目标服务。我们可以很容易地将 web role (VirtualBridge) 与 worker role (Pusher) 合并,只需添加对该程序集(WorkerRolePusher.dll)的引用,并在 ServiceDefinition.csdef
中插入以下部分,当然我们还需要手动将所有 Pusher 的设置插入到 VirtualBridge 设置中。
<Runtime> <EntryPoint> <NetFxEntryPoint targetFrameworkVersion="v4.0" assemblyName="WorkerRolePusher.dll"/> </EntryPoint> </Runtime>
之后,我们可以在同一个实例上运行 VirtualBridge 和 Pusher,这将减少我们在 Azure 上的成本。
最后,我们到了这里。如果一切顺利,我们就可以进入最后一步,即在 Windows Azure 上部署包。
步骤 D:部署到 Azure
这是从 Visual Studio 将包部署到 Azure 的标准步骤。包也可以手动部署,从 Azure Portal 上传。请注意,web role 需要上传您的证书。
结论
本文将 Virtual Bridge 描述为一个应用程序集成器。它为您提供了一个托管在 Azure 上的完整实现解决方案,基于 wcf 自定义 WorkflowChannel。此自定义通道可以将您的 Bridge Definition 投影到托管服务中,如 WCF Routing Service。该解决方案由存储在 Blob 和 Table Storage 中的元数据驱动。这是一种基于 Contract First 概念的强大架构。希望您喜欢。
附录 A - Azure Virtual Bridges Portal
在 Azure 上托管 Virtual Bridges、建模 Bridge Definitions、设置属性、变量、资源、诊断等,都可以通过 portal 进行管理和维护。下图显示了我设计的 Azure Virtual Bridges Portal
的初稿,您可以在其中设计、管理和监控 bridge。
该 portal 是为多租户使用而构建的,用户只能看到他们自己的 bridges 和 variables,具体取决于设置。上面的屏幕截图显示了用户 rikss7
的两个托管 Virtual Bridges(扫描已连接订阅的结果)、他们的 Bridge Definitions、Variables 和 Assemblies。选择一个特定的 definition,我们可以看到 xaml、设置、仪表板等。要编辑(或建模)definition,可以启动 WorkflowDesigner
。每个 definition 也有自己的仪表板,包含日志消息。添加新的 bridge definition 非常直接,只需右键单击 TreeNode。此操作将弹出 VETER 模板存储库,其中包含预定义的 states(如转换、目标等),具体取决于您的登录和订阅。
请注意,此 portal 未包含在本篇文章中。
参考文献:
[1] Announcing the Refresh of Service Bus EAI & EDI Labs
[2] Service Bus EAI and EDI Labs - April 2012 Release
[3] An Introduction to EAI Bridges
[4] WF Azure Activity Pack CTP 1
[5] Using Windows Azure Service Bus Messaging
[6] Setting and Retrieving Properties and Metadata for Blob Resources (REST API)
[7] Windows Azure Service Bus EAI & EDI
[8] How to: Use a Custom User Name and Password Validator
[9] How to Configure an SSL Certificate on an HTTPS Endpoint
[10] Service Bus Explorer