以下主题提供有关适配器正确关闭的指导。
终止适配器
当消息引擎关闭时,它在每个进程内适配器上调用 IBTTransportControl 的 Terminate。 此方法返回后,BizTalk Server 将销毁适配器。 对于本机适配器,这种情况会立即发生,而对于托管适配器,由于 .NET 垃圾回收过程,确切发生的时间更难以预测。 适配器应在 Terminate 中阻止并执行任何必要的清理工作,直到它准备好销毁为止。
终止独立接收适配器
隔离接收适配器不会调用Terminate,因为它们未托管在 BizTalk 服务中。 相反,它们应该调用 IBTTransportProxy.TerminateIsolatedReceiver 来通知消息引擎它们即将关闭。
使用 Marshal.ReleaseComObject 清理 COM 对象
编写使用 COM 对象的托管代码时,公共语言运行时 (CLR) 将生成包含对 COM 对象的引用的代理对象。 代理对象是托管对象,受垃圾回收的常规规则的约束。 出现问题时,垃圾回收器只看到 .NET 运行时分配的内存,并且不知道 COM 对象。 由于代理对象很小,因此大型 COM 对象可能保留在内存中,因为 CLR 垃圾回收器不知道它。
若要避免此问题,请在使用完基础 COM 对象(尤其是任何 IBTTransportBatch 对象)后显式释放基础 COM 对象。 你通过调用 Marshal.ReleaseComObject 来释放 COM 对象。
注释
ReleaseComObject 返回剩余引用的数目,并且仅在返回的值为零时释放 COM 对象。 通常 ,ReleaseComObject 在循环中调用,以确保释放对象。 完成后,您应该对该对象调用 SuppressFinalize,因为没有需要完成的内容。 最后一步是检查这是否确实是 COM 对象。
以下代码显示了上面描述的过程:
if (Marshal.IsComObject (batch))
(
While (0 <Marshal.ReleaseComObject(batch)
;
GC.SuppressFinalize (batch);
显式释放从 GetBatch 返回的 IBTTransportBatch 对象可以显著提高性能。
在关闭适配器时始终使用终止操作
要使 BizTalk Server 能够将代码识别为适配器,必须实现名为 IBTTransportControl 的接口。 此接口定义 BizTalk Server 如何与适配器通信,并定义如下:
public interface IBTTransportControl
{
void Initialize(IBTTransportProxy transportProxy);
void Terminate();
}
该接口包含两种方法: Initialize 和 Terminate。
初始化
BizTalk Server 在加载适配器程序集后调用 Initialize 方法。 这样做是将传输代理(主句柄传递给 BizTalk Server)传递给适配器。 Initialize 的实现只是将传输代理存储在成员变量中。
终止
BizTalk Server 在服务关闭时调用 Terminate 方法,为适配器提供完成所有批处理的执行时间。 这使得 Terminate 方法的实现更加复杂。
适配器在完成任何挂起的工作之前,不应从 Terminate 调用返回。 BizTalk Server 调用 Terminate 时,适配器应尝试停止其所有当前任务,而不启动任何新任务。
由于终止作为服务关闭的一部分被调用,因此,如果适配器在终止中永久阻塞,服务控制管理器将结束进程。 在这种情况下,会看到服务控制管理器发出警告,因为它停止 BizTalk Server 服务。 如果可能,请避免过早终止适配器。 如果适配器未适当处理终止进程,并且进程开始关闭时仍运行线程,则有时可能会在关闭 BizTalk Server 时看到访问冲突。
由于 BizTalk Server 接口的异步性质,因此在负载下可能会有许多批处理,因此线程仍在执行。 应实现 终止 调用以等待适配器在 BizTalk Server 上成功执行的每个批处理的结束,然后再继续。 批处理的结论由 BizTalk Server 中的 BatchComplete 回调发出信号。 终止调用应等待所有挂起的 BatchComplete 完成。 但是,批处理的执行必须成功。 也就是说,对 IBTTransportBatch::Done 的调用不能失败。 如果对 IBTTransportBatch::Done 的调用失败,则没有批处理回调。
意识到必须向适配器添加同步代码后,实现非常简单。
一个简单的方法是实现复合同步对象,该对象包含工作线程的 Enter 和 leave 方法,以及一个 终止 方法,该方法在线程仍在受保护的执行中时阻止。 (顺便说一句,解决方案与熟悉的多读取器单编写器结构非常相似,其中工作线程可以视为读取器, 终止 方法作为编写器)。
终止方法如下所示:
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,其中显示了此处所述的同步机制。