我需要将ASP.NET MVC网站与第三方COM应用程序集成。代码看起来像这样:
Type type = Type.GetTypeFromProgID(progID);
dynamic obj = Activator.CreateInstance(type);
if (!obj.DBOpenedStatus)
{
obj.InitApplicationContext();
//do stuff with other COM objects
}
问题是,一段时间后我开始得到COMExceptions
,因为我从未使用obj.ReleaseApplicationContext()
关闭该上下文。所以我正在考虑编写一个实现IDisposable
的包装器,以便我可以在构造函数中初始化上下文,并在它被处理时释放它。但是我需要一个lock
,以便当前线程仍在工作时,另一个线程不会关闭上下文。代码如下所示:
lock (_locker)
{
using (MyComContextWrapper comContext = new MyComContextWrapper())
{
//do stuff with other COM objects
}
}
我对线程安全知之甚少,所以我问你的是:
编辑1:
我在注册表中查找了COM类的progID,发现ThreadingModel=Apartment
,因此COM应用程序使用Single-Threaded Apartment
类型。
编辑2:
COM应用程序使用系统为对象生成id,以便当这些对象持久存储在数据库中时,它们已经具有Id。该系统涉及在注册表中写入一些信息。过了一会儿这个系统出了问题,我开始收到violation of primary key constraint
错误。
编辑3:
我有时会得到System.ArgumentNullException: Value cannot be null. Parameter name: type at Activator.CreateInstance(Type type)
。这可能是因为我试图从另一个线程创建一个新的STA对象吗?
编辑4:
有人让我发布COMExceptions
的完整堆栈,但我担心这会让我的问题过于本地化,对我以外的任何人都没用。此外,我实际上找到了问题的原因:有一些非常罕见的情况,在使用某些com对象之前未初始化上下文并且这使系统搞砸了,但错误仅在稍后出现。因此,我确保在使用任何com对象之前始终初始化上下文,问题就消失了。
我仍然对线程安全和我提出的解决方案的答案感兴趣。或者问题可能因为过于本地化而被关闭?
答案 0 :(得分:2)
您不应该在对象周围使用锁定,因为COM线程的整个目的是让您的生活更轻松自动(一旦您了解它的使用,并且注册表是正确的)在多线程环境中。 / p>
在标准的托管.NET方案中,您也不需要执行任何特定操作,即使释放COM对象也应由垃圾收集器自动完成。所以你不需要使用模式。
话虽这么说,底层的非托管COM对象可能会在它一旦被使用时释放得更好,或者你的应用程序可能因为某些原因而无法等待GC的发生(例如,因为使用了hi )。在这些情况下,您可以使用Marshal.ReleaseComObject或Marshal.FinalReleaseComObject强制释放COM对象一旦使用,并使用包装器对象进行包装。