我目前正在查看我们在.Net Framework 2.0 Windows服务(C#)中遇到的问题,该服务具有X个运行MTA线程以访问COM组件。每个线程初始化它自己的com组件对象的实例。 com组件对象没有任何UI元素。它只是业务逻辑,它与sql server数据库和带有com接口的C#dll进行通信,而com接口又进行套接字通信并访问同一个sql server数据库。
通过我的研究,我发现你不应该在MTA线程上实例化STA COM组件,但我找不到任何特定的文本来说明这是什么危险或者可能是我不明白的事实COM线程公寓很好。
上面描述的模型会出现并发问题吗?即使每个MTA线程都在创建自己的STA COM对象?
我们实际遇到的问题是对象引用未设置为以下代码块中连接字符串的setter中的对象错误的实例。这发生在c ++ COM对象调用的C#COM对象中:
IDbConnection connection;
//Code omitted for brevity where connection is initialized
connection.ConnectionString = myConnectionString;
异常类型:System.NullReferenceException消息:对象 引用未设置为对象的实例。数据: System.Collections.ListDictionaryInternal TargetSite:Void ConnectionString_Set(System.String)at System.Data.OracleClient.OracleConnection.ConnectionString_Set(字符串 价值) System.Data.OracleClient.OracleConnection.set_ConnectionString(字符串 值)
答案 0 :(得分:11)
从MTA拨打电话时有四种基本的“危险”:
COM对象是单元线程的,非常常见,因此必须将调用封送到拥有该对象的公寓。 “STA COM”的技术上正确的措辞。那是昂贵的,对小方法的编组调用通常要慢10,000倍。
COM对象不支持编组调用的代理。这很容易找到,电话会因E_NOINTERFACE而失败。
客户端程序员没有意识到他正在从MTA拨打电话并忘记编组接口指针。 COM无法阻止对进程内COM服务器的调用。你不能在.NET程序中犯这个错误,CLR总是编组,但在其他运行时环境中很容易做到。否则会调用发生线程不安全调用的常见愤怒,在调试代码时有效,在生产中随机失败并且无法调试。
COM作者通过将ThreadingModel声明为Both或Free来发布他的组件以与MTA兼容。但实际上并没有彻底地测试他的代码,编写线程安全的代码是非常困难的。在[ComVisible] .NET类中特别危险,因为它们会自动注册为Both,并且很容易完全忘记根据该承诺测试代码。
你的片段太难以理解,无法拨打电话,但可能成为第4个子弹的候选人。否则看起来根本不涉及任何COM。像Oracle这样的数据提供者通常是由数十万程序员自由编程和测试的。