2010-10-07 8 views
6

Z tego co rozumiem, gdy komponent COM oznaczony jako używający STA jest używany z wątku MTA, połączenia mają być kierowane do wątku STA i wykonywane z tego dedykowanego wątku. W przypadku aplikacji klienckiej Windows oznaczałoby to, że byłaby ona wykonywana w wątku UI (jeśli jest oznaczona jako STA), a wywołania zwrotne ze składnika COM do mnie byłyby obsługiwane przez wiadomości systemu Windows wysyłane do ukrytego okna i przetwarzane przez pętla komunikatów systemu Windows.W jaki sposób obsługiwane są komponenty STA COM podczas korzystania z usługi WCF hostowanej w IIS (7+)?

Co się stanie, jeśli użyję komponentu STA COM w usłudze WCF hostowanej w IIS? Czy proces roboczy ma pętlę komunikatów systemu Windows na wątku STA? Czy mogę wystrzelić własny wątek STA z własną pętlą komunikatów?

Odpowiedz

4

Środowisko wykonawcze COM zajmuje się wysyłaniem wywołań metod do obiektu COM w STA: masz rację, że jest to oparte na tym samym mechanizmie systemu operacyjnego, który jest używany do wysyłania komunikatów systemu Windows, ale nie musisz się martwić aby tak się stało - COM robi to za ciebie pod maską.

Musisz się martwić o to, do której STA będą używane Twoje obiekty COM. Jeśli tworzysz obiekty COM z powiązanymi mieszkaniami przy użyciu COM Interop z usługi WCF, musisz zachować ostrożność.

Jeśli wątek, w którym to zrobisz, nie jest wątkiem STA, wówczas wszystkie przetwarzane obiekty COM będą domyślnie przechowywane w domyślnym Host STA dla procesu roboczego IIS. Nie chcesz, aby tak się stało: wszystkie obiekty COM dla wszystkich operacji serwisowych znajdą się w tej samej STA. Wskazówka znajduje się w nazwie - istnieje tylko jeden wątek dla wszystkich obiektów - wszystkie wywołania do ich metod będą serializowane, czekając na jedyny wątek w mieszkaniu, aby je wykonać. Twoja usługa nie będzie skalowalna, aby obsłużyć wielu współbieżnych klientów.

Należy upewnić się, że obiekty COM, które są tworzone w celu obsługi określonego żądania WCF, znajdują się w osobnej STA, niezależnie od obiektów tworzonych dla innych żądań. Istnieją zasadniczo dwa sposoby, aby to zrobić:

  • rozpędzają własny wątek z wyszczególnieniem ApartmentState.STA w SetApartmentState() zanim się rozpocznie, na których instancji obiektów COM dla konkretnego wniosku. Jest to podejście opisane przez Scotta Seely'a w the link in Kev's answer: zapewnia on, że każde wywołanie operacji serwisowej jest wywoływane na nowym wątku zainicjowanym przez STA. Mocniejszym, ale bardziej skalowalnym rozwiązaniem w tym zakresie byłoby wdrożenie puli wielokrotnego użytku wątków zainicjowanych STA.
  • Hostuj swoje obiekty COM w aplikacji COM +, aby żyły w oddzielnym procesie DllHost, gdzie COM + (poprzez jego abstrakcję o nazwie the Activity) może zająć się umieszczaniem obiektów dla różnych żądań w różnych stacjach STA.

Nie jestem do końca pewien, co masz na myśli, gdy mówisz o oddzwonieniach. Być może masz na myśli wywołania metody COM na interfejsie COM zaimplementowanym w zarządzanym kodzie, poprzez referencję przekazaną do obiektów COM jako argument do jednej z metod obiektów COM: jeśli tak, to powinno po prostu działać. Ale może masz na myśli coś innego, w takim przypadku być może mógłbyś zmienić pytanie, by wyjaśnić.

3

Odkryłem, że trzeba pompować komunikaty na wątku STA w usłudze WCF lub brakuje wywołań zwrotnych z obiektu COM.

Poniższy kod działa, ale wymaga wywołania obiektu COM za pośrednictwem programu rozsyłającego.

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

Następnie wykonaj połączenia w następujący sposób.

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

'localThreadFinished' nie jest nigdzie zdefiniowane, o ile mogę powiedzieć ... był twój zamiar zadeklarować go na szczycie' ThreadProc', jak 'AutoResetEvent localThreadFinished = (AutoResetEvent) O'? – transistor1

Powiązane problemy