在 IIS (7+) 托管的 WCF 服务中使用 STA COM 组件时,如何处理?

发布于 2024-09-26 19:28:43 字数 451 浏览 6 评论 0 原文

据我了解,当从 STA 的 COM 组件时href="https://en.wikipedia.org/wiki/Component_Object_Model#Threading" rel="nofollow">MTA 线程,调用应该被编组到 STA 线程并从该专用线程执行。对于 Windows 客户端应用程序,这意味着它将在 UI 线程上执行(如果标记为 STA),并且从 COM 组件到我的回调将由发送到隐藏窗口并在Windows 消息循环。

如果我在 IIS 托管的 WCF 服务中使用 STA COM 组件,会发生什么情况?工作进程在 STA 线程上是否会有 Windows 消息循环?我可以用自己的消息循环启动我自己的 STA 线程吗?

From what I understand, when a COM component marked as using STA is used from an MTA thread, the calls are supposed to be marshalled to an STA thread and executed from that dedicated thread. In the case of a Windows client application, this would mean that it would execute on the UI thread (if marked as STA), and that callbacks from the COM component to me would be handled by Windows messages sent to a hidden window and processed on the Windows message loop.

What happens though if I use a STA COM component in a WCF service hosted in IIS? Will the worker process have a Windows message loop on a STA thread? Can I fire up my own STA thread with its own message loop?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

蛮可爱 2024-10-03 19:28:43

COM 运行时负责调度对 STA 内 COM 对象上的方法的调用:您是对的,这基于用于调度 Windows 消息的相同操作系统机制,但您无需担心如何实现这一点 - COM 在幕后为您完成此操作。

需要需要担心的是您的 COM 对象将驻留在哪个 STA 中。如果您使用 WCF 服务中的 COM Interop 实例化公寓线程 COM 对象,则需要小心。

如果执行此操作的线程不是 STA 线程,则所有进程内 COM 对象都将位于默认 托管 STA 用于 IIS 工作进程。您不希望发生这种情况:所有服务操作的所有 COM 对象最终都将位于同一个 STA 中。线索就在名称中——所有对象只有一个线程——并且对其方法的所有调用都将被序列化,等待公寓中唯一的线程来执行它们。您的服务将无法扩展以处理多个并发客户端。

您需要确保实例化以服务特定 WCF 请求的 COM 对象位于其自己的 STA 中,与为其他请求创建的对象分开。大致有两种方法可以做到这一点:

  • 启动您自己的线程,在启动之前在 SetApartmentState() 中指定 ApartmentState.STA,在该线程上实例化 COM 对象一个特定的请求。这是 Scott Seely 在 Kev 答案中的链接:他确保每个服务操作调用都在新的 STA 初始化线程上调用。沿着这些思路,一个更难但更具可扩展性的解决方案是实现一个可重用的 STA 初始化线程池。
  • 将 COM 对象托管在 COM+ 应用程序中,以便它们位于单独的 DllHost 进程中,其中 COM+(通过其抽象称为 Activity) 可以负责将不同请求的对象放入不同的 STA。

当您提到回调时,我不确定您的意思到底是什么。也许您的意思是 COM 方法调用在托管代码中实现的某些 COM 接口,通过作为 COM 对象方法之一的参数传递到 COM 对象的引用:如果是这样,这应该可以工作。但也许你的意思是别的,在这种情况下,也许你可以修改问题来澄清。

The COM runtime looks after the dispatching of calls to methods on a COM object inside an STA: you are right that this is based on the same OS mechanism used for dispatching Windows messages, but you don't need to worry about making this happen - COM does this for you under the hood.

What you do need to worry about is which STA your COM objects are going to live in. If you instantiate apartment-threaded COM objects using COM Interop from a WCF service, you need to be careful.

If the thread on which you do this is not an STA thread, then all in-process COM objects will live in the default Host STA for the IIS worker process. You do not want this to happen: all your COM objects for all service operations will end up in this same STA. The clue is in the name - there is just one thread for all the objects - and all calls to their methods will be serialized waiting for the one and only thread in the apartment to execute them. Your service will not scale to handle multiple concurrent clients.

You need to make sure that COM objects you instantiate to service a particular WCF request are in their own STA separate from objects created for other requests. There are broadly two ways to do this:

  • Spin up your own Thread, specifying ApartmentState.STA in SetApartmentState() before you start it, on which to instantiate the COM objects for a particular request. This is the approach detailed by Scott Seely in the link in Kev's answer: he ensures that each service operation call is invoked on a new STA-initialised Thread. A harder but more scalable solution along these lines would be to implement a pool of reusable STA-initialised Threads.
  • Host your COM objects in a COM+ Application, so that they live in a separate DllHost process, where COM+ (through its abstraction called the Activity) can take care of putting the objects for different requests into different STAs.

I'm not sure exactly what you mean when you refer to callbacks. Perhaps you mean COM method calls on some COM interface implemented in your managed code, via a reference passed in to the COM objects as an argument to one of the COM objects' methods: if so, this should just work. But perhaps you mean something else, in which case perhaps you could amend the question to clarify.

想你只要分分秒秒 2024-10-03 19:28:43

我发现您需要在 WCF 服务中的 STA 线程上泵送消息,否则您会错过来自 COM 对象的回调。

以下代码有效,但需要您通过调度程序调用 COM 对象。

ComWrapper comWrapper;
Thread localThread;
Dispatcher localThreadDispatcher;

public Constructor()
{
   localThread = new Thread(ThreadProc)
   {
       Name = "test"
   };
   localThread.SetApartmentState(ApartmentState.STA);

   AutoResetEvent init = new AutoResetEvent(false);

   localThread.Start(init);

   init.WaitOne();
}

private void ThreadProc(object o)
{
    localThreadDispatcher = Dispatcher.CurrentDispatcher;
    ((AutoResetEvent)o).Set();

    comWrapper = new ComWrapper()

    Dispatcher.Run();

    localThreadFinished.Set();
 }

然后按如下方式拨打电话。

public void UsefulComOperation()
{
    localThreadDispatcher.Invoke(new Action( () => comWrapper.UsefulOperation);
}

I've found that you need to pump messages on your STA thread in a WCF service or you miss callbacks from the COM object.

The following code works, but it requires you call the COM object via a Dispatcher.

ComWrapper comWrapper;
Thread localThread;
Dispatcher localThreadDispatcher;

public Constructor()
{
   localThread = new Thread(ThreadProc)
   {
       Name = "test"
   };
   localThread.SetApartmentState(ApartmentState.STA);

   AutoResetEvent init = new AutoResetEvent(false);

   localThread.Start(init);

   init.WaitOne();
}

private void ThreadProc(object o)
{
    localThreadDispatcher = Dispatcher.CurrentDispatcher;
    ((AutoResetEvent)o).Set();

    comWrapper = new ComWrapper()

    Dispatcher.Run();

    localThreadFinished.Set();
 }

And then make calls as follows.

public void UsefulComOperation()
{
    localThreadDispatcher.Invoke(new Action( () => comWrapper.UsefulOperation);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文