Come vengono trattati i componenti COM STA quando viene utilizzato in un servizio WCF ospitato in IIS (7+)?

StackOverflow https://stackoverflow.com/questions/3880516

  •  28-09-2019
  •  | 
  •  

Domanda

Da quello che ho capito, quando un componente COM contrassegnato come utilizzando STA viene utilizzato da MTA filo, le chiamate si suppone siano radunate a un thread STA ed eseguito da tale thread dedicato. Nel caso di un'applicazione client di Windows, ciò significherebbe che sarebbe eseguire sul thread UI (se contrassegnato come STA), e che le richiamate dal componente COM per me sarebbe stato gestito da messaggi di Windows inviati a una finestra nascosta e trattati su il ciclo di messaggi di Windows.

Cosa succede però se io uso un componente COM STA in un servizio WCF ospitato in IIS? Sarà il processo di lavoro hanno un ciclo di messaggi di Windows su un thread STA? Posso accendere il mio thread STA con il proprio ciclo di messaggi?

È stato utile?

Soluzione

L'aspetto COM runtime dopo l'invio di chiamate a metodi su un oggetto COM all'interno di uno STA: hai ragione che questo si basa sullo stesso meccanismo del sistema operativo utilizzato per l'invio dei messaggi di Windows, ma non è necessario preoccuparsi di fare questo accada - COM fa questo per voi sotto il cofano

.

Quello che do necessità di preoccuparsi è che STA tua COM oggetti stanno andando a vivere in. Se si crea un'istanza di appartamento-threaded oggetti COM con COM Interop da un servizio WCF, è necessario stare attenti .

Se il filo sul quale si esegue questa operazione non è un thread STA, poi tutti in-process oggetti COM Vivrai nel predefinito Host STA per il processo di lavoro IIS. Non si vuole che questo accada: tutti gli oggetti COM per tutte le operazioni di servizio finirà in questo stesso STA. L'indizio è nel nome - c'è un solo filo per tutti gli oggetti - e tutte le chiamate verso i loro metodi verrà serializzato in attesa per l'uno e far passare solo in appartamento per eseguirli. Il vostro servizio non scala per gestire più client simultanei.

È necessario fare in modo che gli oggetti COM si crea un'istanza per servire una particolare richiesta WCF sono nella loro STA separarsi da oggetti creati per altre richieste. Ci sono sostanzialmente due modi per farlo:

  • Spin il proprio Thread, specificando ApartmentState.STA in SetApartmentState() prima di iniziare esso, su cui creare un'istanza gli oggetti COM per una particolare richiesta. Questo è l'approccio descritto da Scott Seely in il link nella risposta di Kev : egli assicura che ogni chiamata operazione di servizio viene richiamata su un nuovo thread sTA-inizializzato. Una soluzione più difficile ma più scalabile lungo queste linee potrebbe essere quella di realizzare un pool di thread STA-inizializzato riutilizzabili.
  • Host tuo oggetti COM in un + Applicazione COM, in modo che essi vivono in un processo DllHost separata, in cui COM + (attraverso la sua astrazione chiamato la Activity) può prendersi cura di mettere gli oggetti per le diverse richieste in diversi STA.

Non sono sicuro esattamente cosa si intende quando si fa riferimento a callback. Forse le chiamate di metodo COM medi su alcuni un'interfaccia COM implementata nel codice gestito, attraverso un riferimento passato per gli oggetti COM come argomento per uno dei metodi degli oggetti COM: se è così, questo dovrebbe funzionare. Ma forse vuoi dire qualcos'altro, nel qual caso forse si potrebbe modificare la domanda di chiarire.

Altri suggerimenti

ho scoperto che è necessario per pompare messaggi sul thread STA in un servizio WCF o ti manca callback dall'oggetto COM.

I seguenti lavori di codice, ma richiede di chiamare l'oggetto COM tramite un 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();
 }

E poi effettuare chiamate come segue.

public void UsefulComOperation()
{
    localThreadDispatcher.Invoke(new Action( () => comWrapper.UsefulOperation);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top