2010-10-07 15 views
6

Por lo que entiendo, cuando un componente COM marcado como usando STA se utiliza desde un subproceso MTA, se supone que las llamadas se organizan en un subproceso STA y se ejecutan desde ese subproceso dedicado. En el caso de una aplicación de cliente de Windows, esto significaría que se ejecutaría en el subproceso de UI (si se marca como STA) y que las devoluciones de llamada del componente COM se manejarían con los mensajes de Windows enviados a una ventana oculta y procesados ​​en el bucle de mensaje de Windows.¿Cómo se manejan los componentes STA COM cuando se usan en un servicio WCF alojado en IIS (7+)?

¿Qué sucede si uso un componente STA COM en un servicio WCF alojado en IIS? ¿El proceso de trabajo tendrá un bucle de mensaje de Windows en un hilo STA? ¿Puedo activar mi propio hilo STA con su propio bucle de mensajes?

Respuesta

4

El tiempo de ejecución COM se ocupa del envío de llamadas a métodos en un objeto COM dentro de una STA: tiene razón en que esto se basa en el mismo mecanismo de SO utilizado para despachar mensajes de Windows, pero no necesita preocuparse haciendo que esto suceda, COM hace esto por ti bajo el capó.

Lo que hace necesidad de preocuparse por lo que es STA sus objetos COM van a vivir. Si usted instancia subprocesamiento objetos COM utilizando interoperabilidad COM de un servicio WCF, es necesario tener cuidado.

Si el hilo en el que hace esto no es un hilo STA, todos los objetos COM en proceso vivirán en el valor predeterminado Host STA para el proceso de trabajo IIS. No quiere que esto suceda: todos sus objetos COM para todas las operaciones de servicio terminarán en esta misma STA. La pista está en el nombre, solo hay un hilo para todos los objetos, y todas las llamadas a sus métodos se serializarán esperando el único hilo en el apartamento para ejecutarlas. Su servicio no se escalará para manejar múltiples clientes concurrentes.

Debe asegurarse de que los objetos COM instanciados para dar servicio a una solicitud WCF determinada estén en su propia STA separada de los objetos creados para otras solicitudes. En términos generales existen dos maneras de hacer esto:

  • girar su propio hilo, especificando ApartmentState.STA en SetApartmentState() antes de comenzar la misma, en la que a instancias de los objetos COM para una determinada solicitud. Este es el enfoque detallado por Scott Seely en the link in Kev's answer: se asegura de que cada invocación de operación de servicio se invoca en un nuevo subproceso inicializado por STA. Una solución más difícil pero más escalable a lo largo de estas líneas sería la implementación de un conjunto de subprocesos inicializados por STA reutilizables.
  • Aloje sus objetos COM en una aplicación COM +, para que vivan en un proceso DllHost separado, donde COM + (a través de su abstracción llamada the Activity) puede encargarse de colocar los objetos para diferentes solicitudes en diferentes STA.

No estoy seguro de a qué se refiere exactamente cuando se refiere a devoluciones de llamada. Quizás te refieres a llamadas al método COM en alguna interfaz COM implementada en tu código administrado, a través de una referencia pasada a los objetos COM como argumento de uno de los métodos de los objetos COM: si es así, esto debería funcionar. Pero quizás quieras decir algo más, en cuyo caso quizás puedas enmendar la pregunta para aclararla.

3

He encontrado que necesita para bombear mensajes en su hilo STA en un servicio WCF o te pierdes devoluciones de llamada desde el objeto COM.

El siguiente código funciona, pero requiere que llame al objeto COM a través de un despachador.

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(); 
} 

Y luego realizar llamadas de la siguiente manera.

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

'localThreadFinished' no se define en cualquier lugar, por lo que yo puedo decir ... era su intención de declarar que en la parte superior del' ThreadProc', como 'AutoResetEvent localThreadFinished = (AutoResetEvent) o'? – transistor1

Cuestiones relacionadas