que - wcf vs web api
¿Cómo se manejan los componentes STA COM cuando se usan en un servicio WCF alojado en IIS(7+)? (2)
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 por hacer que esto suceda. COM hace esto por ti bajo el capó.
Lo que necesita preocuparse es en qué STA sus objetos COM van a vivir. Si crea instancias de objetos COM con rosca de apartamento utilizando COM Interop desde un servicio WCF, debe tener cuidado.
Si el hilo en el que hace esto no es un subproceso STA, todos los objetos COM en proceso vivirán en STA STA predeterminada para el proceso de trabajo de 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 que crea una instancia para prestar servicio a una solicitud WCF particular estén en su propia STA separada de los objetos creados para otras solicitudes. En general, hay dos formas de hacer esto:
-
SetApartmentState()
girar su propio subproceso, especificandoApartmentState.STA
enSetApartmentState()
antes de iniciarlo, en el cual crear una instancia de los objetos COM para una solicitud particular. Este es el enfoque detallado por Scott Seely en el enlace en la respuesta de Kev : se asegura de que cada llamada 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 +, de modo que vivan en un proceso separado de DllHost, donde COM + (a través de su abstracción denominada
Activity
) puede encargarse de colocar los objetos para diferentes solicitudes en diferentes STA.
No estoy seguro exactamente a qué te refieres cuando te refieres a devoluciones de llamada. Quizás te refieres a las 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 para 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 aclarar.
Por lo que entiendo, cuando un componente COM marcado como usar STA se usa desde un hilo de MTA , se supone que las llamadas se distribuirán a un hilo STA y se ejecutarán a partir de ese hilo 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.
¿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?
Descubrí que necesita bombear mensajes en su hilo STA en un servicio WCF o pierde las retrollamadas del 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 realice llamadas de la siguiente manera.
public void UsefulComOperation()
{
localThreadDispatcher.Invoke(new Action( () => comWrapper.UsefulOperation);
}