如何终止适配器

下列主题用于指导您正确关闭适配器。

终止适配器

消息引擎关闭时会调用 IBTTransportControl。在每个进程内适配器上终止 。 此方法返回后,BizTalk Server 会销毁适配器。 本地适配器会立即销毁,而对托管适配器而言,由于存在 .NET 垃圾收集过程,此操作发生的时间没有那么确定。 适配器应在 Terminate 中阻止并执行任何必要的清理工作,直到它准备好销毁为止。

终止独立的接收适配器

独立接收适配器没有调用 Terminate ,因为它们未托管在 BizTalk 服务中。 相反,它们应调用 IBTTransportProxyTerminateIsolatedReceiver 以通知消息引擎它们即将关闭。

使用 Marshal.ReleaseComObject 清理 COM 对象

在编写使用 COM 对象的托管代码时,公共语言运行时 (CLR) 会生成用于保存对 COM 对象的引用的代理对象。 代理对象为托管对象,同时遵循垃圾回收的常用规则。 由于垃圾收集器仅可查看 .NET 运行时分配的内存,而并不会注意到 COM 对象,因而会产生问题。 因为代理对象较小,较大的 COM 对象可能会由于 CLR 垃圾收集器没有注意到它而遗留在内存中。

若要避免此问题,请在使用完基础 COM 对象后显式释放这些对象,尤其是任何 IBTTransportBatch 对象。 可以通过调用 Marshal 来执行此操作。ReleaseComObject

注意

ReleaseComObject 返回剩余引用的数目,并且仅在返回的值为零时释放 COM 对象。 通常,在循环中调用 ReleaseComObject 以确保释放对象。 完成后,应对此对象调用 SuppressFinalize ,因为没有任何可完成的操作。 最后一个步骤是检查此对象是否确实为 COM 对象。

下面的代码演示以上描述的过程:

if (Marshal.IsComObject (batch))  
(  
While (0 <Marshal.ReleaseComObject(batch)  
;  
GC.SuppressFinalize (batch);  
  

显式释放从 GetBatch 返回的 IBTTransportBatch 对象可显著提高性能。

始终使用 Terminate 关闭适配器

若要BizTalk Server将代码识别为适配器,必须实现名为 IBTTransportControl 的接口。 此接口定义 BizTalk Server 如何与您的适配器进行通信,接口的定义方式如下:

public interface IBTTransportControl   
{  
void Initialize(IBTTransportProxy transportProxy);  
void Terminate();  
}  

接口包含两种方法: InitializeTerminate

Initialize

BizTalk Server加载适配器程序集后调用 Initialize 方法。 执行此操作的目的在于将传输代理(BizTalk Server 的主要句柄)传入适配器。 Initialize 的实现只是将传输代理存储在成员变量中。

终止

BizTalk Server服务关闭时调用 Terminate 方法,为适配器提供完成所有批处理的执行时间。 这使得 Terminate 方法的实现更加复杂。

在完成任何挂起的工作之前,适配器不应从 Terminate 调用返回。 当BizTalk Server调用 Terminate 时,适配器应尝试停止其所有当前任务,而不是启动任何新任务。

由于 终止 是在服务关闭过程中调用的,因此,如果适配器在 Terminate 中永久阻止,则服务控制管理器将结束进程。 在这种情况下,在服务控制管理器停止 BizTalk Server 服务时,您会看到其发出的警告。 如果可能,请避免以此方式提前终止适配器。 如果适配器没有正确处理此终止过程,且在该过程开始关闭时还有线程在运行,则在关闭时可能有时会发现来自 BizTalk Server 的访问冲突。

因为 BizTalk Server 接口的异步性,在承受负载的情况下可能还有很多批以及线程需要执行。 应实现 Terminate 调用,以便等待适配器在 BizTalk Server 上成功执行的每个批的结束,然后再继续。 批处理的结论由来自 BizTalk Server 的 BatchComplete 回调发出信号。 Terminate 调用应等待每个挂起的 BatchComplete 发生。 不过,批的执行必须成功。 也就是说,对 IBTTransportBatch::Done 的调用不得失败。 如果对 IBTTransportBatch::Done 的调用失败,则没有批处理回调。

在您发现必须向适配器添加同步代码时,实现就变得相当简单了。

一个简单的方法是实现复合同步对象,其中包含工作线程的 enterleave 方法,以及当线程仍在受保护执行中时阻止的 terminate 方法。 顺便说一句 (,该解决方案非常类似于熟悉的多读取器、单编写器结构,其中可将工作线程视为读取器, 将终止 方法视为 writer.)

terminate 方法如下所示:

void terminate ()  
{  
this.control.Terminate();  
}  

对于每一工作线程:

If (!this.control.Enter())  
return; // we can’t enter because Terminate has been called  
try  
{  
//  create and fill batch  
batch.Done();  
}  
catch (Exception)  
{  
//  we are not expecting a callback  
This.control.Leave();  
}  

在来自 BizTalk Server 的回调中:

batchComplete (…)  
{  
//  the callback from BizTalk Server  
//  process results  
this.control.Leave();  
}  

BizTalk Server基本适配器示例中附带的示例代码 ControlledTermination.cs,其中显示了此处所述的同步机制。