将企业应用程序与托管 BizTalk Services 联系起来
 

2009-07-10 作者:Jon Flanders 和 Aaron Skonnard 来源:microsoft.com

 

目录

与以往相比,当今企业更需要具备快速开发、部署新应用程序以及将其集成到现有环境的能力。企业对动态、松散耦合应用程序的需求日益增长,这正是许多企业转移到或当前正在转移到以面向服务的体系结构 (SOA) 作为其应用程序基础的主要原因之一。

随着公司逐步趋向使用 SOA,人们也越来越重视企业范围内各种应用程序组成的复合系统。在这种新环境下,开发人员负责组织上述各种应用程序服务中的业务流程,它们可能由其他团队和组织开发并发布到网络上,这些团队和组织可能使用不同的实现技术或业务线应用程序,因此增加了整个系统的复杂性。虽然 SOA 可简化每个点对点连接,但复合应用程序却较难以处理且比较脆弱,因为应用程序需要的服务连接总数将随时间增长(请参见图 1)。

图 1 管理复合应用程序中的点对点连接

这一实际情况促使许多公司开始使用更加松散耦合和可持续的服务模式(通常称为企业服务总线 (ESB))。ESB 模型越来越普遍,因为它可通过中央总线来帮助企业管理多项服务连接,这条总线在基本消息传送详情之上提供了一个抽象层。例如,ESB 可帮助代理程序按照命名约定、身份管理、消息格式以及通信协议区分各种服务。一旦服务到达总线,总线上的其他任何服务都可与其建立连接,即使通常无法直接与该服务通信(请参见图 2)。

图 2 使用 ESB 构建复合应用程序

这一模型在总线上各种服务以及复合应用程序与其使用的服务之间引入了一个间接层。ESB 还提供各种消息传送功能,包括发布/订阅功能(可在整个系统中实现更加松散的耦合)。通过发布/订阅功能,使用者无需再直接连接到服务(任何服务只需连接到总线),而且可以根据需要添加或移除节点。通常,ESB 还会提供一个流程引擎,用于协调构成业务流程的消息传送交互活动,这一层通常称为业务流程或工作流。

在 Microsoft 平台中使用 ESB 模式构建系统的一种方式是使用 BizTalk® Server。BizTalk Server 可提供我们在此讨论的所有现有 ESB 功能。

软件即服务

尽管 ESB 在企业范围内越来越普遍,但还有一种业务趋势也在 Web 中迅速蔓延,在未来几年内必将影响企业系统。这种趋势称为软件即服务 (SaaS),以在 Web(有时称为 Internet 云)上提供完整应用程序或服务的所有公司为中心,其他公司只需支付费用即可使用这些应用程序或服务。这样,使用者便可避免构建或管理类似软件所产生的复杂性和成本(设计、开发、操作和维护成本),这类软件通常需要大量初始投资。

SaaS 模型实际上允许使用者远程访问由在某一特定领域(如 CRM、会计、薪金、数据存储、电子邮件等)具有专长的公司托管的软件,如图 3 所示。提供商通常使用 SaaS 针对特定的软件需求提供完整的解决方案,允许使用者外包系统的特定部分。服务提供商会随着时间的推移不断对软件进行管理,只向使用者收取一定的使用费,这意味着使用者无需本地管理这些软件服务。

图 3 使用 SaaS 外包软件需求

SaaS 提供商提供的应用程序或服务通常使用标准 Web 协议和数据格式,以提高其易用性并扩大其潜在的使用范围。当今,它们越来越倾向于使用 HTTP 和常用的 Web 数据格式,如 XML、RSS 和 JSON,它们在今天都非常普遍。虽然 SaaS 不会将提供商限制在这些特定选择上,但范围需求通常迫使提供商沿此方向发展。

有些架构师可能会问使用 SaaS 系统体系结构固有的外部依赖关系是否明智。虽然他们可能担心连接性和服务级别协议 (SLA),但随着今天 Internet 连接的普及,考虑到在 Web 中公开软件所带来的新机遇,这种做法似乎完全可被接受,甚至非常有优势。

Internet 服务总线

Microsoft 已经采用了这些普遍的概念(ESB 和 SaaS),并将它们最引人注目的特征融合成了一种新的概念,称为 Internet 服务总线 (ISB)。ISB 模型在功能上与 ESB 类似。不过,ISB 模型可用于的 Internet 范围更广,因此在标准、范围和可伸缩性方面,它与 SaaS 模型类似。简言之,Microsoft® ISB 使公司可更加轻松地采用 ESB 基础结构。

虽然 ESB 功能正在大范围的公司内进行推广,但似乎对于大型公司而言更具优势。这主要归结于大规模采取某种基础结构(如 ESB)所产生的前期投资和财务风险。实际上,许多公司会转而创建自己的自定义系统集成基础结构,但通常成本更高。这正是今天 BizTalk Server 推广面临最大困难之一。

此外,能够实施 ESB 的公司还会面临尝试使其 ESB 与其合作伙伴的 ESB 通信的难题。所有 ESB 实例都存在差别,这使得难以实现跨企业集成,即使使用松散耦合的 ESB 模式亦是如此。

Microsoft ISB 平台通过在 Internet 云中放置关键服务总线以供公共使用(不考虑使用此组件的平台)解决了这一实际问题。Microsoft 实际上通过 SaaS 模型实现服务总线,从而允许任何规模的公司连接到总线。ISB 提供了发布/订阅体系结构和必要的消息传送基础结构以遍历企业防火墙和网络地址转换器 (NAT)。ISB 还提供了联合身份管理和工作流服务层以承载 Web 中的自定义业务流程,如图 4 所示。

图 4 基于新的 Internet 服务总线构建

Microsoft 正在积极致力于实现 ISB,您可以访问 BizTalk Services 网站了解最新情况(请参见 labs.biztalk.net)。当前的社区技术预览版 (CTP) 提供了一些基本服务,您可以立即开始体验它们。在未来几年内,Microsoft 打算在更加丰富的通信结构中推广此计划,以便为各种现代连接应用程序提供功能强大的构建块。

不过请记住,作为 CTP,现在所提供的功能仅供试验和收集反馈,并不会投入生产使用。Microsoft 此时不提供任何质量保证。此外,Microsoft 尚未宣布 ISB 准备好投入生产使用后,如何对其收费。

BizTalk Services

BizTalk Services 是驻留在 Web 上的 ISB 组件的最初实现。现在,BizTalk Services 由一些核心服务构成,包括 BizTalk 连接服务和 BizTalk 标识服务。另一项重要服务称为 BizTalk 工作流服务,在不久的将来即将推出。随着时间的推移,Microsoft 会不断增加更多服务,第三方也会将其他服务置于 ISB 中。

我们来详细讨论一下当前其中各个核心服务。创建松散耦合的复合应用程序时最富挑战的问题之一是,管理在网络级别如何连接服务。例如,您可能有一个服务位于网络外围中,另一个服务位于防火墙内,并且它们需要互相通信。或者,您可能要对企业合作伙伴公开一项服务,但那些合作伙伴服务位于其自己的防火墙后或其他网络设备中,如代理或 NAT。

BizTalk 连接服务针对服务提供通用的命名约定,并在两个节点之间提供独立于网络拓扑和配置的直接/间接通信机制,借此简化了许多通信难题。为此,它为通过网络设备进行的安全中继连接提供了一种受控机制。也就是说,在可以进行直接连接的情况下,BizTalk 连接服务还会尽量让节点进行无需中继通信的连接。

您当然可以自己编写此类型的代码,但这可能非常艰巨,而且繁琐。允许 BizTalk Services 提供此功能的主要优势在于您不必编写或维护该代码,它们通常会根据端点自定义。这使您可以集中精力编写代码来解决您的业务问题,而不必针对这些基础结构问题编写代码。BizTalk 连接服务还可提供其他重要功能,例如基于统一资源标识符 (URI) 的全局命名约定、简单的发布/订阅机制,甚至多播功能。

BizTalk Services 的另一个核心部分是 BizTalk 标识服务,这是一项符合 WS-Trust 标准的可公共访问的安全令牌服务 (STS)。WS-Trust 是基于双方之间信任关系协商安全性的可互操作标准。例如,一方可能对客户端进行身份验证,并发出一个令牌,其中包含一些有关该客户端的声明。然后,可向碰巧也信任最初发出令牌一方的其他方安全出示此令牌。此方法可实现跨组织界限联合重要的标识信息。

鉴于此,即使您没有使用类似 BizTalk 连接服务的其他任何功能,仍可将 BizTalk 标识服务用作第三方标识和身份验证管理服务。不过,在使用其他 BizTalk Services 时,BizTalk 标识服务将始终用于对用户进行身份验证和授权。

在使用 BizTalk 连接服务时,将使用用户名/密码、客户端证书或托管卡根据 BizTalk 标识服务对客户端和服务都进行身份验证。通过身份验证后,将会执行一组授权规则以发布一个新令牌,该令牌会提供给 BizTalk 连接服务。BizTalk Services 网站提供了一个用户界面来管理您的授权规则,还提供了一些编程 API,其中包括 REST 式接口。

BizTalk 工作流服务尚未面向大众发行使用。不过,将来的 BizTalk Services 版本预期会提供该功能,以在 ISB 中承载基于 Windows® Workflow Foundation (WF) 的工作流服务。工作流将基于 ISB 在特定 URI 处收到的消息进行激活。当前,只有这些详细资料可用。

BizTalk Services SDK

BizTalk Services SDK 可从 biztalk.net 免费下载。借助它,您可以针对 ISB 开始编程。在开始编程之前,您需要安装 BizTalk Services SDK,并在 BizTalk Services 站点创建一个用户帐户。BizTalk Services 基于 Windows Communication Foundation (WCF) 构建。SDK 是基于 Microsoft .NET Framework 3.0 构建的一组程序集,允许您通过 WCF 编程模型使用 ISB。

大多数 BizTalk Services SDK 存在于 System.ServiceBus 程序集中。System.ServiceBus 使用标准 WCF 扩展点来定义名为 RelayBinding 的新绑定。对于不熟悉 WCF 的编程人员来说,绑定将确定服务端点公开或使用哪种通信。WCF 运行库将使用这些绑定创建通信层(称为通道堆栈),用于发送和接收消息。通道堆栈中的对象执行网络通信,并且确定如何对特定端点实施安全性及其他协议。

在侦听器端,借助 RelayBinding,您可以公开可通过 BizTalk 连接服务支持的全局 URI 访问的端点。打开使用 RelayBinding 的端点时,将向 BizTalk 连接服务注册该 URI,并从该点向前,任何授权的客户端都能使用具有类似配置的客户端向该全局 URI 发送消息。这样,BizTalk 连接服务即成为两个端点之间的通信管道。

典型的 WCF 应用程序

我们来详细介绍一个简单示例。假设我们是一家公司,并且当前我们在内部网络中公开了一项从丰富的客户端应用程序调用的 WCF 服务。该客户端应用程序可供销售人员用于处理订单。该应用程序调用此服务,然后此服务启动完成订单所需的后端处理。

此服务当前配置了一个使用 NetTcpBinding 的端点,可通过 TCP/IP 实现高速连接。通常,对于在防火墙内运行服务,NetTcpBinding 往往是最佳选择。

下面是使用标准 ServiceHost 配置端点并启动服务的代码:

ServiceHost sh = new ServiceHost(typeof(SalesService));
sh.AddServiceEndpoint(typeof(ISalesService), 
  new NetTcpBinding(),
  "net.tcp://salesservicehost/SalesService");

sh.Open();
...

这是标准的 WCF 代码。服务实现是 SalesService 类型,约定是 ISalesServices。调用 AddServiceEndpoint 时创建的 ServiceEndpoint 使用 NetTcpBinding,地址为:net.tcp://salesservicehost/SalesService。

除以这种方式对端点硬编码外,我们还可以在应用程序的配置文件中配置端点(通常会采取这种方式)。不过,此示例通过代码执行所有操作,可能更加容易。下面是一个调用 SalesService 处理销售的示例客户端应用程序:

static void MakeSale(SaleData sd) {
  EndpointAddress ea = new EndpointAddress(
    "net.tcp://salesservicehost/SalesService");
  ChannelFactory<ISalesService> cf = 
    new ChannelFactory<ISalesService>(new NetTcpBinding(), ea);
  ISalesService service = cf.CreateChannel();
  service.EnterSale(sd);
}

随着时间的推移,销售人员的移动性越来越大,并且在他们外出并连接到随机网络(其中一些不允许使用虚拟专用网 (VPN) 连接)时无法连接以处理订单,因此相关报告也逐渐出现。

BizTalk Services 能够解决此问题。我们来看看它采取什么措施通过 BizTalk 连接服务公开 SalesService:

ServiceHost sh = new ServiceHost(typeof(SalesService));
sh.AddServiceEndpoint(typeof(ISalesService), 
  new RelayBinding(),
  "sb://connect.biztalk.net/services/contososervices/SalesService");

sh.Open();
...

您可以看到,为了通过 BizTalk Services 公开此服务,我们要做的就是更改一行调用 ServiceHost.AddServiceEndpoint 的代码。我们使用 RelayBinding(而不是 NetTcpBinding),它使用 BizTalk 连接服务向指定 URI 处的环境公开此端点。然后,发送到该地址的消息将中继到本地 SalesService 实例。

请注意 URI 的格式 — 它以“sb”架构开始,后面是 BizTalk Services 主机名称,然后是“services”。之后,我们添加 BizTalk Services 标识(我们设置的帐户名称),在此例中是 contososervices。然后,我们可以根据需要在 URI 中添加任何内容,以使其独一无二。在此,我们仅附加了 SalesService。

当调用 ServiceHost.Open 时,RelayBinding 将促使 WCF 与 BizTalk 标识服务通信以便对服务标识进行身份验证,并授权允许其在指定的 URI 上侦听。此时,默认行为是促使 Windows CardSpace™ 选择器出现,要求人们选择表示服务标识的卡。

事实上,在身份验证期间出现 UI 对于大多数服务而言显然是禁止的,因为它们通常在无人参与的环境(即无人登录到计算机)中运行。不过,我们可以借助一小段代码来解决此问题。稍后我们将为您提供此段代码,因此请不必担心。现在,我们只是选择一个卡,以使 SalesService 能够开始侦听。您可以使用 BizTalk 标识服务管理在特定的 URI 上允许侦听哪些标识。

现在,我们来看一下将采取什么措施更新客户端,以便它能占用 BizTalk Services 端点:

static void MakeSaleISB(SaleData sd) {
  string uri =   
    "sb://connect.biztalk.net/services/contososervices/SalesService";
  ChannelFactory<ISalesService> cf = new ChannelFactory<ISalesService>(
    new RelayBinding(), new EndpointAddress(uri));
  ISalesService service = cf.CreateChannel();
  service.EnterSale(sd);
}

请注意,除使用 RelayBinding 和指定服务总线 (sb://...) URI 外,客户端与服务完全相同。默认情况下,客户端还会查看 Windows CardSpace 选择器,允许客户端选择一个标识,然后将其发送到 BizTalk 标识服务进行身份验证和授权。如果授权允许此客户端向指定的 URI 发送消息,BizTalk 标识服务将返回一个指示此情况的令牌,然后该令牌传递到 BizTalk 连接服务作为证明。

在此方案中使 Windows CardSpace 选择器出现似乎完全可以接受,因为它是交互式客户端应用程序。同样,您可以使用 BizTalk 标识服务管理允许将哪些客户端标识发送到特定的 URI。

当 BizTalk 连接服务收到来自授权的发送方的传入消息后,它可以轻松地将该消息中继到本地运行的 SalesService 实例。事实上,您无需介意它如何执行操作,因为它是一种实施详情,在将来很可能会改变。不过,在这种情况下,RelayBinding 使用 WCF 的 TcpTransport 连接到 BizTalk 连接服务。当中继消息时,BizTalk 连接服务可通过现有的 TCP 连接返回本地服务实例。

为什么会如此简单?因为 BizTalk 连接服务利用标准 WCF 扩展点来封装连接性,并为客户端和新 RelayBinding 中的服务中继逻辑。事实上,采用 WCF 编程模型的实际优势之一在于,您可以通过轻松地更改绑定(完全可以在配置中实现)来更改基本通信。

中继连接性选项

RelayBinding 对象的重要属性之一是 ConnectionMode。该属性的类型是名为 RelayedConnectionMode 的枚举。此设置确定如何与 BizTalk 连接服务建立连接。BizTalk 连接服务允许发送方和接收方之间存在多种通信模式,这样便为特定的通信方案提供了很大的灵活性(请参见图 5)。

图 5 RelayBinding ConnectionMode 选项

ConnectionMode 值 说明
RelayedOneWay 设置此连接仅可接受或发送单向操作。要使用此设置,您的服务约定中的所有方法必须具有 OperationContractAttribute,其中 IsOneWay 属性设置为“true”。
RelayedDuplex 设置此连接可支持请求-答复约定(包括双向约定)。
RelayedDuplexSession 与 RelayedDuplex 相同,但配置为使用 WS-ReliableMessaging。
DirectDuplexSession 与 RelayedDuplexSession 相同,但进行了优化。发送方和接收方之间的初始连接将使用 BizTalk 连接服务,但随后它将尝试在两个节点之间建立直接连接(如果可能)。如果可以进行直接连接,发送方和接收方将直接通信,中间不再使用 BizTalk 连接服务。如果无法进行直接连接,BizTalk 连接服务将继续提供通信中继。
RelayedMulticast 设置此连接可提供发布/订阅功能。当使用此模式时,多个侦听器可注册到同一个地址。要使用此设置,您的服务约定中的所有方法必须具有 OperationContractAttribute,其中 IsOneWay 属性设置为“true”。
RelayedHttp 此连接设置为通过 BizTalk Services 公开 HTTP 端点以中继回本地网络内计算机上运行的服务,即使该服务通常无法通过 Internet 访问。

RelayedOneWay 适用于单向消息传送方案,因此您只能在标有 IsOneWay=true 的操作中使用此模式。另一方面,RelayedDuplex 适用于请求-答复方案(包括双向约定)。RelayedDuplexSession 与 RelayedDuplex 大致相同,但它还可在通道堆栈内实现可靠的消息传送。这是默认连接模式,因此我们在上一示例中实际上使用的是此模式。此外,DirectDuplexSession 模式是对 RelayedDuplexSession 的优化,它尝试在发送方和接收方之间建立直接连接(如果可能)。如果无法建立直接连接,它将使用中继通信。

我们将详细介绍后两个连接模式。首先,RelayedMulticast 通过 WCF 实现发布/订阅功能,这是在任何内置 WCF 绑定中都不能获得的通信模式。另外,RelayedHttp 允许您公开企业防火墙内或 NAT 后基于 HTTP 的端点,这是自 Web 服务出现以来开发人员一直为之奋斗的通信模式。

当 RelayedMulticast 由第一个侦听器指定时,BizTalk 连接服务允许多个侦听器在同一 URI 处注册。具有侦听同一 URI 的端点的每个 ServiceHost 都将隐式成为订阅者。当客户端向该 URI 发送消息时,该消息将传递到当前订阅的所有服务端点。使用 RelayedMulticast 时事实上只有一个约束,即同 RelayedOneWay 一样,所有操作必须标有 IsOneWay=true。

我们返回到上一个销售应用程序。假设我们该期间定期更新出售的不同项目的价格。我们需要向所有销售人员广播新的价格,以便他们能立即知晓。为实现此操作,每个客户端应用程序可以启动一个 ServiceHost,并使用 RelayBinding(ConnectionMode 设置为 RelayMulticast)侦听同一个 URI:

ServiceHost sh = new ServiceHost(typeof(PriceUpdateService));
sh.AddServiceEndpoint(typeof(IPriceUpdateService),
  new RelayBinding(RelayConnectionMode.RelayedMulticast),
  "sb://connect.biztalk.net/services/contososervices/priceupdate");
sh.Open();
...

当应用程序启动时,每个客户端都将运行此代码,因而所有客户端应用程序都将成为发送到 sb://connect.biztalk.net/services/contososervices/clientupdate 的消息的订阅者。每个客户端现在都是此约定和 URI 的一项订阅服务。在此方案中,后端系统扮演 WCF 客户端的角色,并向所有订阅者广播(发布)消息,如下所示:

static void DoPriceUpdate(PriceUpdate pu) {
  EndpointAddress ea = new EndpointAddress(
    "sb://connect.biztalk.net/services/contososervices/priceupdate");
  ChannelFactory<IPriceUpdateService> cf = 
    new ChannelFactory<IPriceUpdateService>(
      new RelayBinding(RelayConnectionMode.RelayedMulticast), ea);
  IPriceUpdateService service = cf.CreateChannel();
  service.UpdatePrice(pu);
}

当调用 UpdatePrice 时,PriceUpdate 消息将发送到 BizTalk 连接服务,BizTalk 连接服务然后会将该消息中继到当前订阅到同一 URI 的所有服务。

通过 RelayedHttp 穿过防火墙

通过 RelayedHttp 模式,您可以采取本地网络中运行的 HTTP 服务,并可通过 BizTalk 连接服务借助 HTTP 将其公开到公共 Web 中,即使该服务通常不能从您的网络之外直接访问。在与 .NET Framework 3.5 中提供的新 WCF Web 编程模型一同使用时,此功能尤其便捷。

通过这一新的 Web 编程模型,可以借助 WCF 更加轻松地实现 REST 式 Web 服务。它还提供了将您的 WCF 服务与现有 RSS/Atom 以及目前 Web 中使用的 AJAX 基础结构轻松集成的功能。BizTalk Services 不要求使用 .NET Framework 3.5,但考虑到这些新的 WCF 功能,如果已安装 .NET Framework 3.5,RelayedHttp 模式可以提供更多功能。

回到销售应用程序,有时销售人员没有运行丰富的客户端应用程序,但是它们仍需要获得最新价格信息的通知。公开经常更新的数据的一种有趣方式是通过 Web 源,即向了解如何使用这些源的应用程序返回众所周知的 XML 格式,如 RSS 或 Atom 的 HTTP 端点。源阅读器(将 Web 源聚合到面向人的用户界面程序的通用名称)会按设定的日程轮询 Web 源以获取新内容。这样,最终用户就可以通过查看其源阅读器来接收更新,而无需主动导航到该站点。

使用 WCF Web 编程模型,我们可以轻松地构建公开价格更新数据的 Web 源。我们首先需要一个使用新的 WCF 属性实现 HTTP 调用的约定。这些属性会通知 WCF 消息传送层如何基于 URI(而非 SOAP Action 标头)将传入的 HTTP 请求路由到服务的方法。下面是一个示例:

[ServiceContract]
public interface IPriceUpdateFeed {
  [OperationContract()]
  [WebGet(UriTemplate = "*")]
  Atom10FeedFormatter GetPriceUpdate();
}

在此,WebGetAttribute 告知 WCF 每当服务收到 HTTP GET 请求时应调用此方法(与 SOAP 请求相对,它始终使用 HTTP POST)。

另请注意 WebGetAttribute 中的 UriTemplate 属性。该属性将准确告知 WCF 如何将传入消息基于传入请求的 URI 路由到不同方法。此示例使用通配符模板 (“*”) 来指示我们希望将所有 GET 请求路由到此特定方法。您可以轻松地在一个服务中配置多个方法,其中每个方法处理不同的 UriTemplate。当还需要响应 GET 之外的其他 HTTP 动词(包括 POST、PUT、DELETE 和 HEAD)时,您还可以使用 WebInvokeAttribute。

关于此约定,还需要注意此方法的返回类型。WCF Web 编程模型包括一些新类型,专门旨在帮助生成目前的标准源格式。目前支持的两种主要格式是 Atom 和 RSS。此处的示例使用的是 Atom 格式。

图 6 显示了生成 Atom 整合源的 GetPriceUpdate 操作的简单实现。此实现使用新的 SyndicationFeed API 生成逻辑源,然后将其封装在 Atom10FeedFormatter 对象中返回以便生成正确的 XML 格式。

图 6 生成 Web 源

public Atom10FeedFormatter GetPriceUpdate() {
  SyndicationFeed feed = new SyndicationFeed("Product Update Feed",
    "", null);
  List<SyndicationItem> items = new List<SyndicationItem>();
  feed.Items = items;
  IEnumerable<Product> products = GetUpdatedProducts();
  string iText = "Product update for {0}. Old price={1}. New Price={2}";
  foreach (var product in products) {
    items.Add(new SyndicationItem("Product update for " + product.Name,
      String.Format(iText, product.Name, product.OldUnitPrice,   
      product.UnitPrice),
      null, 
      product.Name, 
      product.UpdatedTime));
  }
  return new Atom10FeedFormatter(feed);
}

现在,我们需要配置一个端点来侦听这些请求。WCF 3.5 中包括一个新绑定类,可以非常轻松地配置端点。WebHttpBinding 类将封装有关创建 REST 式通道堆栈(SOAP 消息不适用)的详细信息。它仅使用来自 WCF 的 HTTP 传输和基于文本的消息编码器,并将编码器的消息版本设置为“None”。下面是连接并运行新端点所需的代码:

ServiceEndpoint se = 
  sh.AddServiceEndpoint(typeof(IPriceUpdateFeed), 
  new WebHttpBinding(), "http://localhost:8099/ProductFeed");
se.Behaviors.Add(new WebHttpBehavior());
...

请注意,WebHttpBinding 端点使用 WebHttpBehavior 实例配置,该实例将基于 HTTP 的必要调度逻辑注入到了运行库。一旦启动并运行配置了新端点的 ServiceHost,则可以浏览到服务在 localhost:8099/ProductFeed 处侦听的 HTTP URI,并且应可以看到 Atom 源。

现在,假设我们要对不在内部网络的销售人员公开此源。我们可以轻松地使用 BizTalk 连接服务将 HTTP 通信中继到我们的本地服务,而不必再通过防火墙公开此计算机。我们可以通过使用 RelayBinding 添加另一个端点来完成此操作,而不必为 ConnectionMode 指定 RelayedHttp,如下所示:

ServiceEndpoint se = 
  sh.AddServiceEndpoint(typeof(IPriceUpdateFeed),
  new RelayBinding(RelayConnectionMode.RelayedHTTP),
  "http://connect.biztalk.net/services/contososervices/ProductFeed");
se.Behaviors.Add(new WebHttpBehavior());
...

完成这些操作后,现在我们可以安全地在公共 Web 上公开服务,但此逻辑由内部服务器托管。在图 7 中,您可以看到可通过 Internet 访问的公共 URI 公开的此源。当然,该源看起来完全相同,现在途中的销售人员可订阅此源并获得更新,而不会再遇到有关 VPN、防火墙或网络等任何复杂问题。

7 通过 BizTalk 连接服务公开 HTTP 服务

配置标识服务

无论对 RelayBinding 使用哪种连接模式,都必须根据 BizTalk 标识服务对侦听器(服务)和发送方(客户端)进行身份验证和授权。身份验证是根据一组初始声明确定客户端或请求程序身份的过程。授权是针对一组初始声明应用一组用户定义的授权规则的过程。

授权规则可通过一系列声明转换轻松地生成一组新声明(每个规则将一组输入声明映射到一组输出声明)。最初一组输入声明是由请求程序提供给 BizTalk 标识服务的声明。目前,BizTalk 标识服务支持三种类型的初始声明组:用户名/密码、客户端证书和托管卡。在使用用户名/密码的情况下,用户名是初始声明,而密码是该声明的证据。

BizTalk 标识服务将从用户名声明开始处理授权规则以生成输出声明。随着新声明的生成,它们可充当其他规则的输入声明,呈现一定程度的规则链。最后一组输出声明包含在 BizTalk 标识服务返回的令牌中。当您尝试访问 BizTalk 连接服务时,必须提供特定的输出声明。

您还可以使用证书配置 BizTalk 标识服务,以保护其生成的令牌。配置证书时,将使用来自证书的公钥对提供给请求程序的令牌加密,因此通过线路传递将更加安全,且在传输过程中更不易被客户端篡改。

可通过几种方式配置这些授权规则。一种方式是通过 BizTalk Services 网站提供的 UI(请参见图 8)。另一种方式是以编程方式使用 SDK 中提供的身份管理 API。最近,还发布了该接口的 REST 式版本。

图 8 BizTalk Services 网站声明映射 UI

在配置授权规则时,您需要考虑如何使用 BizTalk 标识服务。同样,您可以将 BizTalk 标识服务用作通用 STS 或 BizTalk 连接服务访问控制机制。

将 BizTalk 标识服务用作通用 STS 时,您可以将传入的用户名输入声明映射到任何输出声明。输出声明将置于生成的令牌中,然后可提供给其他方。当以此方式使用 BizTalk 标识服务时,您必须至少有一个规则,其中输入声明是用户名。您可以基于新的输出声明添加更多级联规则(例如,将用户名规则生成的输出声明用作另一输出声明的输入声明),从而允许您建立一组任意输出声明。请参见 BizTalk Services SDK 中的 AccessControl 示例来了解一个完整的示例。

为使用 BizTalk 连接服务进行身份验证,您需要确保使用几个特定规则配置 BizTalk 标识服务。如上所述,您必须至少有一个规则,其中输入声明是用户名,并且您还可以使用级联规则。

不过,如果 BizTalk 连接服务是唯一的,预计要在最后一个令牌中查找 Resource#Operation 输出声明,其中资源必须是服务的侦听 URI,而操作必须是 Listen 或 Send。例如,{URI} #Listen 允许用户在指定的 URI 上启动服务端点侦听,而 {URI} #Send 允许用户向指定的 URI 发送消息。

自定义令牌提供程序

前面我们提到过,当服务器开始侦听时,服务器应用程序中通常很少会出现交互式登录屏幕,如 Windows CardSpace 选择器。出现这种情况是因为每个使用 RelayBinding 的端点使用的是实现 ITokenProvider 接口的对象。此接口的默认实现是 CardspaceTokenProvider,它将导致在连接到 BizTalk 连接服务时出现 Windows CardSpace 选择器。

除 CardspaceTokenProvider 之外,SDK 还另外包含一些 ITokenProvider 实现。UsernameTokenProvider 使用来自 BizTalk 标识服务的注册用户名和密码检索令牌。AutomaticRenewalTokenProvider 将导致 Windows CardSpace 选择器出现,但在当前令牌到期之前会自动获取一个新令牌,从而实现“配置一次”端点。这两个实现也是端点行为,可以添加到客户端或服务端点替换默认的 CardspaceTokenProvider。

现在,通过在调用 ServiceHost.Open 之前配置端点的 UsernameTokenProvider,我们的服务可以避免交互式登录,如下所示:

ServiceHost sh = new ServiceHost(typeof(SalesService));
ServiceEndpoint se = sh.AddServiceEndpoint(typeof(ISalesService),
  new RelayBinding(),
  "sb://connect.biztalk.net/services/contososervices/SalesService");
UsernameToken token = new UsernameTokenProvider("someusername", 
  "somepassword");
se.Behaviors.Add(token);
sh.Open();
...

现在,无论何时服务进程启动,都可以自动使用 BizTalk 标识服务进行身份验证,不用任何人为干预。此外,还可以通过将实现作为端点行为添加轻松地在 RelayBinding 端点上配置其他 ITokenProvider 实现(SDK 中的 TokenProvider 基类实现 ITokenProvider 和 IEndpointBehavior)。


火龙果软件/UML软件工程组织致力于提高您的软件工程实践能力,我们不断地吸取业界的宝贵经验,向您提供经过数百家企业验证的有效的工程技术实践经验,同时关注最新的理论进展,帮助您“领跑您所在行业的软件世界”。
资源网站: UML软件工程组织