6

我需要将 ASP.NET MVC 网站与第 3 方 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. 我的方法有什么问题吗?
  2. 还有什么我应该考虑的(比如死锁或其他)?
  3. 你会推荐一种不同的方法吗?

编辑 1:
我在注册表中查找了 COM 类的 progID,发现ThreadingModel=ApartmentCOM 应用程序使用了一个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 对象之前始终初始化上下文并且问题消失了。

我仍然对有关线程安全的答案和我提出的解决方案感兴趣。或者这个问题应该因为过于本地化而被关闭?

4

1 回答 1

2

您不需要在对象周围使用锁,因为 COM 线程的全部目的是在多线程环境中让您的生活更轻松和自动化(一旦您了解了它的使用,并且注册表是正确的)。

在标准托管 .NET 方案中,您也不需要执行任何特定操作,即使释放 COM 对象也应该由垃圾收集器自动完成。所以你不应该需要使用模式。

话虽如此,底层的非托管 COM 对象在使用后可能会更好地工作,或者您的应用程序可能由于某种原因不能真正等待 GC 发生(例如,由于使用 hi )。在这些情况下,您可以使用Marshal.ReleaseComObjectMarshal.FinalReleaseComObject来强制释放使用过的 COM 对象,并使用包装器对象对其进行包装。

于 2012-12-27T13:53:40.060 回答