SoapMSMQ Transport for WSE 3.0






4.52/5 (10投票s)
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.msmq
和 soap.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
寻址的可能用法:
- 通过本地私有队列 '
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);
- 通过 MSMQ 广播地址 234.1.1.1 和端口 4455 将消息发送到所有地址为
urn:myReceiver
的Endpoints
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);
- 通过 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) 在通道层之间进行消息交换:
- 请求 (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());
注意:以下示例使用两个私有事务性队列 - ReqChannel
和 RspChannel
。
示例 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 支持这些模式。让我们描述它们的使用。
- 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 的更多详细信息)。
- 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。