65.9K
CodeProject 正在变化。 阅读更多。
Home

SoapMSMQ Transport for WSE 3.0

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.52/5 (10投票s)

2005年11月15日

CPOL

16分钟阅读

viewsIcon

95639

downloadIcon

1033

WSE 3.0 的 soap.msmq 传输更新,消息交换模式的配置和使用。

 

 

SoapMSMQ Transport WSE 3.0 技术的更新。

 

目录

 

引言

Web Services Enhancements (WSE) 3.0 是微软的一款产品,它支持使用最新技术(如 Visual Studio 2005 和 .Net Framework 2.0)构建安全的 Web 服务和消息驱动的连接模型。它基于 2.0 SP3 版本以及与 Windows 2k/XP 及更高平台的新通信基础模型 (WCF) 的互操作性需求而开发。请注意,由于 WCF (Indigo) 仅在 Windows 2k3/XP 及更高平台上运行,因此 WSE 3 将使您能够使用基于 WS-* 规范的消息命名空间来构建 Win2k 及更高平台之间的连接系统。

WSE 3.0 仅内置了通过 http 和 tcp 协议交换消息的传输方式,并且可以有或没有 Http 服务器托管。可以根据开放的消息模型,通过编程或管理方式构建自定义传输,并将其插入 WSE 3.0 的层栈中。

现代企业应用程序模型可以使用事件驱动的架构设计,将业务工作流封装到预处理、处理和后处理活动中。所有活动都应该完全封装业务逻辑,并移至底层通信模型。微软为异步处理提供了非常稳定的技术,例如 MSMQ 3.0(请注意,其功能已为 WCF 模型增强 - MSMQ 3.5 的 beta 版本)。

我基于 MSMQ 3.0 功能构建了一个适用于 WSE 2.0/SP3 的 SoapMSMQ Transport。其概念、设计和实现细节可在此处下载:这里

本文着重介绍 SoapMSMQ Transport 向 WSE 3.0 版本的迁移、配置和使用。我假设读者熟悉 WSE 2/3 和 MSMQ 技术。

 

特点

  • 请求消息模式 (单向)
  • 请求 - ReplyTo 消息模式 (2x 单向)
  • 上下文驱动模式
  • 多个事务性请求
  • DTC 事务性请求
  • 事件驱动监听器
  • 并发接收器
  • 未送达处理程序
  • MSMQ 3.0 支持
  • 可配置属性

 

迁移到 WSE 3.0

迁移 SoapMSMQ (WSE 2/SP3 版本) 进行了以下小的更改:

  • 替换命名空间
  • 将 SoapDimeFormatter 替换为 SoapPlainFormatter 作为默认格式化器
  • 移除了 WSE 2SP3 错误的解决方法,该错误与基于 EndpointReference 键从 SoapReceivers 集合获取接收器有关。
  • 在派生通道类中移除覆盖方法 Capabilities
  • 在 WSDL 文档请求的传输中添加新方法 SoapBindingTransportUri
  • 修复了 Request/Response 消息的 msmq 相关消息 ID,其中在 RelatesTo 标识符中添加了 guide schema (uuid)。
  • 使用 Transaction 命名空间
  • 添加新功能 - 在配置文件中更改格式化器的选项(内置格式化器或自定义格式化器)
  • 基于 WCF (Indigo) 标准化 soap.msmq 传输寻址

 

配置

soap.msmq 传输属性被缓存到 SoapMsmqTransportOptions 对象中。可以通过编程方式或使用宿主进程配置文件覆盖 Options 对象中每个属性的默认值,如下面的代码片段所示。

<configuration>
 <configSections>
    <section name="microsoft.web.services3" 
        type="Microsoft.Web.Services3.Configuration.WebServicesConfiguration, 
        Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35" />
 </configSections>
 <microsoft.web.services3>
  <diagnostics />
  <messaging>
   <transports>
    <add scheme="soap.msmq" 
        type="RKiss.WseTransports.SoapMsmqTransport, 
        SoapMSMQ, Version=3.0.0.0, Culture=neutral, PublicKeyToken=1019d5a553d1e207">
     <transactional enabled="true" />
     <formatter type="SoapPlainFormatter" />
     <sender>
      <adminQueue path=".\private$\adminchannel" />
      <toBeReceived timeInSec="30" />
      <toBeReachQueue timeInSec="5" />
      <toBeReplied timeInSec="120" />
      <useDeadQueue enabled="true" />
      </sender>
      <receiver>
       <workerThreads number="3" />
       <errorQueue path=".\private$\reqchannel_error" />
      </receiver>
    </add>
    <add schema="soap.null"
         type="RKiss.WseTransports.SoapNullTransport, 
         SoapNULL, Version=3.0.0.0, Culture=neutral, PublicKeyToken=1019d5a553d1e207" />
   </transports>
  </messaging>
 </microsoft.web.services3>
</configuration>

上面的配置文件显示了两个自定义传输的配置:soap.msmqsoap.null

配置文件中 soap.msmq 传输的配置节被分为通用、发送方和接收方节。请注意,属性名称区分大小写,并且传输类型必须位于同一行。

soap.msmq 传输可以通过以下属性进行配置:

名称和默认值 传输 注意
<transactionalenabled="true"/> 发送方和接收方 发送方和接收方将以事务方式处理消息。
<formatter type="SoapPlainFormatter" /> 发送方和接收方 WSE 3.0 格式化器的名称或自定义格式化器的完整限定类型
<adminQueue path=""/> sender 超时消息的管理队列。
<toBeReceived timeInSec="0"/> sender 接收器检索消息的超时限制。
<toBeReachQueue timeInSec="0"/> sender 消息传递到目标队列的超时限制。
<useDeadQueue enabled="true"/> sender 使用死信队列的选项。
<workerThreads number="1"/> 接收器 检索消息的工作线程数,最大数量为 25。
<errorQueue path=""/> 接收器 接收器异常队列(非 SoapEnvelope 等)。
     

 

终结点传输地址

soap.msmq 传输 URI 地址格式必须具有正确的语法来构建 MSMQ 格式名称。soap.msmq 传输可以使用以下格式:

URI 地址 (示例) 注释
soap.msmq:///private/MyQueue 本地计算机上的私有队列。
soap.msmq://MyServer/private/MyQueue MyServer 计算机上的私有队列。
soap.msmq://MyServer/MyQueue MyServer 计算机上的公共队列。
soap.msmq://127.0.0.1/private/MyQueue 由 IP 地址定义的计算机上的私有队列。
soap.msmq://234.1.1.1:4455 广播 (组播) 消息到此 IP 地址和端口指定的队列。
soap.msmq://MyServer/msmq/private/MyQueue 通过 Internet 的私有队列。
soap.msmq://127.0.0.1:1234/private/MyQueue 由 IP 地址和端口指定的计算机上的私有队列。
soap.msmq://./MyQueue 本地计算机上的公共队列。

 

以下示例展示了 soap.msmq 寻址的可能用法:

  1. 通过本地私有队列 'MyQueue' 将消息发送到终结点,地址为 urn:myReceiver
     
     EndpointReference epr = new EndpointReference(new Uri("urn:myReceiver"));
     epr.Via = new Uri(@"soap.msmq:///private/reqchannel"));
     SoapSender Sender = new SoapSender(epr);
     Sender.Send(message); 
                    
  2. 通过 MSMQ 广播地址 234.1.1.1 和端口 4455 将消息发送到所有地址为 urn:myReceiverEndpoints
     
     EndpointReference epr = new EndpointReference(new Uri("urn:myReceiver"));
     epr.Via = new Uri(@"soap.msmq://234.1.1.1:4455"));
     SoapSender Sender = new SoapSender(epr);
     Sender.Send(message); 
                    
  3. 通过 Internet 上的私有队列 'MyQueue' 将消息发送到终结点 urn:myReceiver (请注意,服务器必须启用 MSMQ 组件才能使用此功能)
     
     EndpointReference epr = new EndpointReference(new Uri("urn:myReceiver"));
     epr.Via = new Uri(@"soap.msmq://MyServer/msmq/private/MyQueue"));
     SoapSender Sender = new SoapSender(epr);
     Sender.Send(message); 
                    
 
 

SoapEnvelope Context for soap.msmq transport

soap.msmq 传输有能力根据契约属性通过 SoapEnvelope 上下文进行控制。下表显示了在发送方/接收方可用的属性。

名称 类型 使用方 注意
TransactionId 字符串 接收器 MSMQ 事务 ID。
IsFirstInTransaction 布尔值 接收器 true,如果消息是单个/多个事务中的第一条。
IsLastInTransaction 布尔值 接收器 true,如果消息是多个事务中的最后一条或单个事务中的最后一条。
致谢 object 接收器 收到的消息所代表的确认的分类。
MessageQueueTransaction object 发送方 接收方 提供消息队列内部事务 (MSMQ) 的对象。
MessageLabel 字符串 发送方 接收方 消息标签

 

以下示例展示了上述上下文属性的用法:

  • 用于识别消息在多个事务中的位置的示例
    bool first = Convert.ToBoolean(message.Context[SoapMSMQ.IsFirstInTransaction]);
  • 用于设置 MSMQ 消息标签的示例 (适合故障排除)
    envelope.Context.Add(SoapMSMQ.MessageLabel, "This is a test label");
                    

用法

SoapMSMQ Transport 支持以下消息交换模式 (MEP) 在通道层之间进行消息交换:

  1. 请求 (Datagram) - 这是一种单向 MEP,发送方以“发送即忘”的方式发送消息。下图显示了此消息模式。

    

    SoapClient 使用 SendOneWay 方法以“发送即忘”的方式执行请求消息,而不等待其回复。此调用以同步方式完成,因此客户端仅拥有消息处理的信息 (状态)。上图显示了此活动称为 AsyncWorkflow 的逻辑模式。有两种活动:

  • SyncActivity 负责准备业务数据、状态和唯一的 Workflow Context (如果不存在则创建),用于业务处理。此活动也称为 Pre-Pocessor。Workflow Context 可以存储在共享存储中,也可以通过消息传递。工作流标识符作为 Ticket 返回给客户端,用于后续关联。请注意,消息代表工作流中的有状态对象。
  • AsyncActivity 是执行和更新工作流状态的业务流程。

工作流活动在逻辑上连接,允许基于连接活动流动工作流上下文并交换消息。SoapMSMQ Transport 是此逻辑连接的物理实现,具有异步活动。让我们从几个示例开始,展示由 soap.msmq 传输驱动的此逻辑连接。

以下所有示例均假定使用相同的 SoapService 来执行业务处理(单向和请求-应答模式)。请注意,EchoResponse 方法用于 ReplyTo 消息模式示例。

class MyService : SoapService
{
   [SoapMethod("Bar")]
   public void Bar(string text)
   {
      Console.WriteLine(text);    
   }

   [SoapMethod("Echo")]
   public string Echo(string text)
   {
      string response = "ServiceEcho: " + text;
      Console.WriteLine(response);    
      return response;
   }
   
   [SoapMethod("EchoResponse")]
   public void EchoResponse(string text)
   { 
      string response = "ServiceEchoResponse: " + text;
      Console.WriteLine(response);    
   }
} 

针对特定终结点地址的服务注册

EndpointReference epr = new EndpointReference(new Uri("urn:myService")); 
epr.Via = new Uri(@"soap.msmq:///private/reqchannel");
SoapReceivers.Add(epr, new MyService());                

 

注意:以下示例使用两个私有事务性队列 - ReqChannelRspChannel

 

示例 1.1 - 简单的异步工作流

基于上述描述,以下代码片段显示了用于 SyncActivity 处理的 Pre-processor 示例。Bar 方法代表业务方法,可以在其中包含业务逻辑。在我们的示例中,有四个步骤。在方法的 prolog 中,我们创建了一个工作流 ticket 和一些业务预处理。在步骤 2 中,我们将工作流头附加到目标寻址,然后发送一个 Datagram,最后(epilog)我们将 ticket 返回给调用者。

class SimpleClient : SoapClient
{
   public SimpleClient (EndpointReference destination) : 
      base(destination){}
   public SimpleClient (Uri address, Uri via) : 
      base(new EndpointReference(address, via)) {}

   [SoapMethod("Bar")]
   public string Bar(string text)
   {
      // step 1 - Prolog: some business pre-processing
      string ticketId = Guid.NewGuid().ToString();
      string reqtext = string.Concat(ticketId, ": ", text);

      // step 2: attach workflow context
      Destination.ReferenceProperties = WorkflowContext(ticketId);

      // step 3 Action: send datagram 
      base.SendOneWay("Bar", reqtext);

      // step 4 Epilog: return a ticketId back to the caller
      return ticketId;
   }

   private ReferenceProperties WorkflowContext(string ticketId) 
   {
      // example of the workflow context
      XmlDocument doc = new XmlDocument();
     doc.LoadXml(string.Format(
         @"<wsa:ReferenceProperties xmlns:wsa='{0}'>
             <ticketId>{1}</ticketId>
           </wsa:ReferenceProperties>", WSAddressing.NamespaceURI, ticketId));
      return new ReferenceProperties(doc.DocumentElement);
   }
}            

现在,如果我们有一个 Pre-processor,则以下代码片段显示了其用法:

 EndpointReference epr = new EndpointReference(new Uri("urn:myReceiver"));
 epr.Via = new Uri(@"soap.msmq:///private/reqchannel");

 SimpleClient simpleClient = new SimpleClient(epr);
 string ticketId = simpleClient.Bar("This is a Datagram message");

 // todo: next business action                

 

Bar 方法发送的 Datagram 在 MSMQ 资源管理器下是事务性的。消息将在步骤 3 中立即传递。实际上,在大多数情况下,SyncActivity 会处理多个资源,如数据库、MSMQ、文件系统等。在这些情况下,有必要使用事务范围以 ACID 方式执行工作流。让我们在以下示例中修改我们的 SimpleClient 以实现此功能。

  

示例 1.2 - 简单的 DTC 异步工作流

在同步工作流活动中添加资源将需要使用 DTC 事务协调器进行两阶段提交。我们的异步工作流将如下所示。在此示例中,这两个业务操作都包含在 SyncActivity 中,同时使用企业数据库共享工作流和业务状态。这是事件驱动架构中最常见的模式。

 

   

 

现在,根据业务需求,SynchActivity 可能需要创建新事务或成为事务上下文的一部分。在下面的代码片段中,SyncActivity 被要求成为新事务范围的根,因此其提交不依赖于调用者的事务上下文。

[SoapMethod("Bar")]
public string Bar(string text)
{
   string ticketId = string.Empty;
   
   using (TransactionScope txscope = 
      new TransactionScope(TransactionScopeOption.RequiresNew, TimeSpan.FromSeconds(20)))
   {
      // step 1 - Prolog: some business pre-processing
      ticketId = Guid.NewGuid().ToString();
      string reqtext = string.Concat(ticketId, ": ", text);

      // step 2: attach workflow context
      Destination.ReferenceProperties = WorkflowContext(ticketId);

      // step 3 Action: send datagram 
      base.SendOneWay("Bar", reqtext);

      // step 3a Action 2: update database
      // Simulation 
      Console.WriteLine("Press key 'a' to abort this workflow or any key to continue ...");
      if(Console.ReadKey(true).Key == ConsoleKey.A)
         throw new Exception("The workflow has been aborted");

      // done
      txscope.Complete();
   }

   // step 4 Epilog: return a ticketId back to the caller
   return ticketId;
}
             

正如我们所见,Bar 方法有两个由 soap.msmq 传输和数据库(模拟为键盘)等资源操作的 Action(步骤 3 和 3a)。发送 Datagram(将消息插入队列)取决于成功的事务,表示通过调用 TransactionScope.Complete 方法。所有资源将在 txscope 关闭时提交。此时,Datagram 将发送到目标队列。对于远程队列,Datagram 会暂时存储在 MSMQ 管理器的本地 Outgoing 队列中,然后通过网络传递到目标队列。请注意,发送失败不会回滚事务,应使用业务补偿器来恢复数据或状态。

 

示例 1.3 - 多个 (后台) DTC 异步工作流

.net 2.0 Transaction 命名空间简化了事务的使用。此示例展示了实现事务性后台活动是多么简单直接。事务性 SyncActivity 预处理器可以将活动委托给事务性相关工作线程,并提交它们,直到所有工作线程完成。

 在此情况下,Bar 方法代表事务性父活动,其中创建了工作线程并将其传递给 ThreadPoolQueue 进行处理。每个工作线程都有自己由业务逻辑和工作流上下文填充的状态。

之后,父事务范围完成,并等待来自各个工作线程(活动)的投票。所有工作线程必须完成,否则父事务将被中止。

以下代码片段显示了 Bar 方法的实现。

[SoapMethod("Bar")]
public string[] Bar(string text)
{
   int numberOfTx = 5;
   string[] ticketIds = new string[numberOfTx];
   using (TransactionScope txscope = 
      new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromSeconds(20)))
   {
      // run backgroud dependent transactions
      for (int ii = 0; ii < numberOfTx; ii++)
      {
         MyState mystate = new MyState();
         mystate.dtx = 
            Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
         mystate.ticketId = Guid.NewGuid().ToString();
         mystate.text = text;
         mystate.ii = ii;
         ThreadPool.QueueUserWorkItem(new WaitCallback(MyWorker), mystate);
         ticketIds[ii] = mystate.ticketId;
      }

      // done
      txscope.Complete();
   }

   // step 4 Epilog: return a ticketId back to the caller
   return ticketIds;
}

以下代码片段显示了工作线程的实现。它看起来像原始的 Bar 方法,但事务范围是从父事务依赖项创建的,因此有必要执行两次提交,如范围内的事务和然后是依赖事务。请注意,父事务的行为可以根据业务需求进行配置,例如 BlockCommitUntilComplete 和 RollbackIfNotComplete。

public void MyWorker(object state)
{
   try
   {
      MyState mystate = state as MyState;
      using (TransactionScope txscope = new TransactionScope(mystate.dtx))
      {
         // step 1 - Prolog: some business pre-processing
         string reqtext = string.Concat(mystate.ii, ", ", mystate.ticketId, ": ", mystate.text);

         // step 2: attach workflow context
         Destination.ReferenceProperties = WorkflowContext(mystate.ticketId);

         // step 3 Action: send datagram 
         base.SendOneWay("Bar", reqtext);

         // step 3a Action 2: update database
         //Console.WriteLine("Press key 'a' to abort this workflow or any key to continue ...");
         //if (Console.ReadKey(true).Key == ConsoleKey.A)
         //   throw new Exception("The workflow has been aborted");

         // done
         txscope.Complete();
      }
      mystate.dtx.Complete();
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex);
   }
}
internal class MyState
{
   public DependentTransaction dtx;
   public string ticketId;
   public string text;
   public int ii;
}    

Datagram 消息模式就是这些。Datagram 消息表示源和目标之间的基本通信模式。在此基础上,可以创建其他消息交换模式,如 Request-ReplyTo 和 Request-Response。SoapMSMQ Transport 支持这些模式。让我们描述它们的使用。

 

  1. Request-ReplyTo - 基于两个 Datagram。发送方发送一个 Datagram (Request) 消息,并带有 ReplyTo 终结点地址,而不等待其响应。这是事件驱动架构中最常见的消息模式。基于 ReplyTo 地址,AsyncActivity 负责将业务处理器通知 Datagram 或结果发送到指定的终结点,以完成 AsyncWorkflow。工作流活动的最后一个状态 (PostActivity) 称为 Post-Processor。下图显示了 Request-ReplayTo 消息模式。

 

    

此模式以 Push 模型方式在工作流活动之间转发消息。当前活动只需要知道下一个活动 (ReplyTo 终结点地址)。在特殊情况下,PostActivity 也可以是 SyncActivity,换句话说,后处理器和预处理器可以合并到一个 SyncActivity 中,从而允许工作流上下文的流动和链接。

下图显示了链接的 AsyncWorkflows。

    

 

最后一个 PostActivity 的特殊情况可以是 Datagram 广播 - 通知消息。soap.msmq 传输支持此功能。广播消息是一种非常有用的消息模式,适用于未知数量的订阅者或隐式扩展环境,如集群。下图显示了带有广播 PostActivity 的 ReplyTo 模式。

    

 

示例 2.1 - 简单的 Request-ReplyTo 异步工作流

我们可以通过在我们的测试 SimpleClient 类中添加以下 Echo 方法来处理 Request-ReplyTo 消息模式。

[SoapMethod("Echo")]
public void Echo(string text)
{
   EndpointReference eprReplay = new EndpointReference(new Uri("urn:myReceiver"));
   eprReplay.Via = new Uri(@"soap.msmq:///private/reqchannel");
   SoapEnvelope envelope = new SoapEnvelope();
   envelope.SetBodyObject(text);
   envelope.Context.Addressing.ReplyTo = new ReplyTo(eprReplay);
   base.SendOneWay("Echo", envelope);
} 
    
    

如上面的代码片段所示,Echo 方法发送了一个请求 Datagram,并指定了接受其 Response 的终结点地址。这种非常强大的消息模式受 WS-* 规范支持。它是事件驱动架构的完美模式。基于 DataContract,Response 载荷可以携带业务结果或通知(工作流状态)可用性。请注意,此模式也支持 DTC 事务(请参见上面的示例 1.2 和 1.3 的更多详细信息)。

 

  1. Request - Response - 这是 Request-ReplyTo 消息模式的一个特殊情况,客户端(请求的发送方)在指定时间段内等待响应 Datagram 本身。此模式称为半双工通信。RequestResponse 消息模式的用法仅适用于连接的系统(服务和其消费者必须在响应时间内物理连接)。soap.msmq 传输支持此 MEP 来与 Biztalk 等应用程序通信。下图显示了 RequestResponse 消息模式。

 

    


消息交换的概念基于内部 SoapClientAsyncResult 类,该类发送请求并在超时限制内等待其响应。当然,客户端需要为此消息模式填充 ReplyTo 地址。

 

示例 3.1 - 简单的 Request/Response 异步工作流

通过在我们的测试 SimpleClient 类中添加以下 Echo 方法,我们可以处理 Request-Response 消息模式:

[SoapMethod("Echo")]                
public string Echo(string text)
{
   EndpointReference eprReplay = new EndpointReference(new Uri("urn:myClient"));
   eprReplay.Via = new Uri(@"soap.msmq:///private/rspchannel");
   SoapEnvelope envelope = new SoapEnvelope();
   envelope.SetBodyObject(text);
   envelope.Context.Addressing.ReplyTo = new ReplyTo(eprReplay);
   return (string)base.SendRequestResponse("Echo", envelope).GetBodyObject(Type.GetType("System.String"));
}
        

请注意,必须创建 ReplyTo 终结点地址并将其分配给 Request 消息。从客户端的角度来看,所有消息交换在 RPC 方式下完全透明,看起来就像通过 tcp 或 http 进行传输。

DTC Request-Response 消息呢?

嗯,答案很简单 - 不可能。客户端将等待一个永远不会收到的响应消息,因为 Request datagram 无法在事务范围内提交(发送到目标队列)。对于 DTC 事务来说,这是完全正确的行为。基本上,有三种 MSMQ 事务:预处理器、处理器和后处理器。我们不能将预处理器和后处理器活动组合在同一个事务上下文中。

测试

SoapMSMQ Transport 可以使用简单的控制台程序进行测试,例如客户端和服务器。它们包含在下载中。请注意,客户端有许多注释掉的测试选项,其代码仅为测试目的而编写得“粗糙”!

以下屏幕截图显示了服务器和客户端宿主进程的启动测试。运行测试之前,请确保您的计算机具有以下资源:

  • .Net 2.0
  • 已安装 WSE 3.0
  • SoapMSMQ Transport (msi 包)
  • 私有事务性队列: ReqChannel, RspChannel, ReqChannel2, ReqChannel_Ack, ReqChannel_Error

 

       

 

  

 

 

结论

在 Web Enterprise Application 中使用异步工作流可以创建分布式中间层,其中 Web 服务扮演着重要角色。WSE 3.0 是一种可以实现面向服务架构 (SOA) 驱动模型的技术。将业务逻辑与连接性分离,可以创建逻辑模型连接,从而可以根据需要部署物理层。SoapMSMQ Transport 可以成为此层次结构的一部分。

我将以一种不同寻常的方式结束本文 - 展示 soap.msmq 传输在典型的集群 Web 应用程序中的另一个用法,其中用户提交请求并等待其响应。在过去的 5 年里,通过 Web 服务访问业务的案例急剧增加。访问单个资源(本地或企业数据库)的典型 3 层架构已被 Web 服务和 SAO 改变。我们可以看到中间层带来了新的维度 - **分布式中间层**。

前端呢?

嗯,典型的同步 Request/Response 在现实世界中将无法正常工作,因为以松散耦合方式访问分布式资源不能得到保证,前端将超时。在 Web 应用程序中使用异步工作流是一个合适的解决方案,可以将业务工作流划分为同步和异步部分。同步部分始终处理本地资源,因此接受用户请求非常快。一旦应用程序接受请求,异步活动就可以在分布式中间层进行处理。这是一个典型的 Push 模型模式。

前端呢?前端如何获取响应?这段时间前端在做什么?等等。

这些问题是正确的。请记住,前端只能使用 Pull 数据模型模式。在非事件驱动架构中,轮询模式的概念基于定期访问数据库中的响应。此解决方案存在许多基于业务需求的副作用。

是否有另一种更好的方法来获取响应,例如以同步方式?

是的,有。使用事件驱动架构,其中异步活动将生成一个通知,用于后处理活动以完成业务工作流。下图显示了一种在集群环境中使用的设计模式,该模式对 WebGardens 及其进程以及 WebFarms 完全透明。

 

 

 

上述设计的概念基于 soap.msmq 传输与组播通知消息。前端等待(或等待+轮询)WebFarm 上的本地资源,如配置了组播监听器的本地(私有)通知队列。一旦通知消息到达,前端就可以从数据库中获取响应(业务结果)。等待时间可以使用进度条在浏览器中进行动画处理(例如,http://www.expedia.com/ 所做的)。从用户的角度来看,这看起来像一个同步请求。这种伪同步设计模式允许更好地利用本地资源而不丢失提交的请求。例如,当用户在业务处理过程中关闭浏览器并重新打开时,可以通过一次数据库访问来恢复进程。

这就是 soap.msmq 传输的全部内容。我正在研究 soap.null 传输,它允许通过管理方式(基于配置元数据)构建异步工作流样板,并将其分成单独的服务(活动),如 Pre-Pocessor、Processor 和 Post-Processor。一如既往,我将把它们发布到 codeproject。

 

© . All rights reserved.