使用 BizTalk Server 2010 和 ESB Toolkit 2.1 的经典发布-订阅解决方案





5.00/5 (1投票)
本文旨在通过 ESB 工具包为经典的发布-订阅问题提供一种替代解决方案。
您是 BizTalk Enterprise Service Bus (ESB) 2.1 Toolkit 的新手吗?
如果是,请阅读我的 “Hello World” ESB 文章,它将带您入门。
案例研究:一个简单的发布-订阅场景
考虑一种场景,其中需要将 **联系人** 信息发布给多个订阅者。问题在于将联系人更新消息发送给多个订阅者。解决此问题的经典方法是,让 **消息代理编排** 将多个消息放入消息框。然后,这些消息将被发送端口订阅或其他编排消费,以满足量身定制的解决方案。
在本文中,我将尝试使用 ESB 工具包提出一种不同的解决方案。

考虑一种场景,其中需要将自定义 **联系人** 更新消息发送给多个订阅者。这里的订阅者是两个 CRM 系统。其思路是首先将消息转换为 **规范** 形式(如通用联系人)。然后,将此 **规范** 联系人转换为各自的 CRM 特定格式。
自定义联系人消息
自定义 contact
消息**不是**规范形式,这是从应用程序收到的 RAW XML。必须使用转换映射将其转换为规范形式。

理解行程
在这种情况下使用行程有什么好处?
- 无需修改现有的 BizTalk 部署配置,即可向行程添加新的订阅者。
- 可以使用 BRE 规则更改订阅者端点。
- 可以使用 BRE 规则更改订阅者数据格式(映射)。
- ESB 入站(On-Ramp):ESB 入站接收消息。这是需要转换为规范形式的自定义联系人消息。
- ESB 消息扩展器(Message Extender):此形状用于将自定义联系人消息转换为规范联系人。
- ESB 编排扩展器(Orchestration Extender):此形状用于使用编排处理规范联系人,并使用订阅者列表进行分派。解析器(Resolvers)会列出订阅者列表。
- ESB 出站(Off-Ramp Extender):出站扩展器用于将规范消息归档到存档文件夹。
- ESB 出站(Off-Ramp):BizTalk Server 动态发送端口(也称为 ESB 出站)用于将规范消息放入存档文件夹。
如何在行程中找到转换映射?

转换映射是通过行程形状解析器配置中的 BRE 解析器策略
找到的。BRE 策略将如下所示,请注意映射的完全限定名称。
BRE 策略:ContactCanonicalMap
//##Conditions
If Context_Receive_Port_Name == "ContactInfo" and _
Context_Receive_Location_name == "ContextLocation:FILE"
//##Actions
Set Transform_Type To "MyCustomerSchema.CustomerContact_To_ContactCanonical_Map, _
MyCustomerSchema, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2710b190689828fa"
BizTalk ESB 兼容的“分派器”编排
步骤 1:消息框绑定
需要一个直接绑定到消息框的逻辑接收端口来接收 ESB 消息。联系人 **规范** 消息由编排接收。
步骤 2:编码编排的核心部分
为简洁起见,编排已分为两个部分。一个用于 **解析器处理**,另一个用于 **推进行程**。
初始化
// Itinerary - Initialize
itineraryWrapper = new Microsoft.Practices.ESB.Itinerary.SerializableItineraryWrapper();
itineraryStepWrapper =
new Microsoft.Practices.ESB.Itinerary.SerializableItineraryStepWrapper();
// Itinerary - Assign
itineraryWrapper.Itinerary =
Microsoft.Practices.ESB.Itinerary.ItineraryOMFactory.Create(InboundMsg);
itineraryStepWrapper.ItineraryStep = itineraryWrapper.Itinerary.GetItineraryStep(InboundMsg);
// Itinerary - Extract
hasNextService = itineraryWrapper.Itinerary.HasNextService();
resolvers = itineraryStepWrapper.ItineraryStep.ResolverCollection;
// Resolver - Count
System.Diagnostics.Trace.WriteLine("Resolver count: " +
System.Convert.ToString(resolvers.Count), eventSource);
第一部分:遍历所有解析器
这是编排中最关键的部分。其思路是遍历所有 **解析器** 并将 **转换后** 的消息分配给动态发送端口。
// Move to retrieve first resolver
resolver = resolvers.Current;
// Pass the resolver configuration to the Resolver mgr for resolution
resolverDictionary =
Microsoft.Practices.ESB.Resolver.ResolverMgr.Resolve(InboundMsg, resolver);
// set transport properties
transportLocation = resolverDictionary.Item("Resolver.TransportLocation");
transportType = resolverDictionary.Item("Resolver.TransportType");
mapType = resolverDictionary.Item("Resolver.TransformType");
自定义逻辑:您可以添加自定义逻辑来根据某些规则确定合适的 订阅者
。
//Retrieve map type from resolution structure
mapCLRType = System.Type.GetType(mapType);
transform(OutboundMsg) = mapCLRType(InboundMsg);
OutboundMsg(*) = InboundMsg(*);
Microsoft.Practices.ESB.Adapter.AdapterMgr.SetEndpoint(resolverDictionary, OutboundMsg);
// Set delivery port address
RoutingDynamicPort(Microsoft.XLANGs.BaseTypes.Address) = transportLocation;
RoutingDynamicPort(Microsoft.XLANGs.BaseTypes.TransportType) = transportType;
第二部分:推进行程到下一步
此操作会将消息发送回行程以执行其他步骤。如果行程没有其他附加步骤,则不会执行该操作。

OutboundMsg.Body = InboundMsg.Body;
OutboundMsg(*) = InboundMsg(*);
itineraryWrapper.Itinerary.Advance(OutboundMsg, itineraryStepWrapper.ItineraryStep);
itineraryWrapper.Itinerary.Write(OutboundMsg);
System.Diagnostics.EventLog.WriteEntry(eventSource, "Message posted back to ESB.");
步骤 3:在 esb.config 中添加条目
在 C:\Program Files (x86)\Microsoft BizTalk ESB Toolkit 2.1 下找到 esb.config,找到 XML 标签 itineraryServices
并添加以下内容
<itineraryservice id="cbd59fc2-e8e0-4d00-ad73-8590938911b2" stage="None"
scope="Orchestration" type="ContactOperation.Dispatcher, ContactOperation,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=2710b190689828fa"
name="ContactOperation.Dispatcher" />
要点:使用 ESB Toolkit 快速转换消息的两种方法是什么?
使用 Transform XLANG 关键字
//Retrieve map type from resolution structure
mapCLRType = System.Type.GetType(mapType);
//Executing a map using transform keyword
transform(OutboundMsg) = mapCLRType(InboundMsg);
注意:'mapCLRType'
是一个类型为 'System.Type'
的变量。
使用 'MapHelper.TransformMessage' API 调用
transformedData = Microsoft.Practices.ESB.Transform.MapHelper.TransformMessage
(InboundMsg.Body.OuterXml, MetadataMsg.Body.TransformationType);
注意:'transformedData'
是一个类型为 'System.String'
的变量。
一些需要思考的点
- **不建议** 在
行程
中使用编排。行程
的设计**不鼓励**使用编排。期待关于更好解决方案的建议,该方案在本文所述情况下避免在行程中使用编排。 - 任何优雅的设计都清晰地描绘了端到端的邮件流处理,即从源到目的地。
行程
是其中一种看待方式。通过使用行程,我们正在模拟端到端的邮件流。 - 流经 ESB 的每条消息都会附带一个行程。
- 使用 BRE 解析器可以灵活地在邮件流过程中使用映射。