Opis zmian stanu

W tym temacie omówiono stany i przejścia, które kanały mają, typy używane do struktury stanów kanału i sposób ich implementowania.

State Machines and Channels

Obiekty, które zajmują się komunikacją, na przykład gniazda, zwykle przedstawiają maszynę stanu, której przejścia stanu odnoszą się do przydzielania zasobów sieciowych, nawiązywania lub akceptowania połączeń, zamykania połączeń i końcowania komunikacji. Maszyna stanu kanału zapewnia jednolity model stanów obiektu komunikacji, który abstrakcji podstawowej implementacji tego obiektu. Interfejs ICommunicationObject udostępnia zestaw stanów, metod przejścia stanu i zdarzeń przejścia stanu. Wszystkie kanały, fabryki kanałów i odbiorniki kanału implementują maszynę stanu kanału.

Zdarzenia Zamknięte, Zamykające, Uszkodzone, Otwarte i Otwierające sygnalizuje zewnętrzny obserwator po przejściu stanu.

Metody Abort, Close i Open (i ich odpowiedniki asynchroniczne) powodują przejścia stanu.

Właściwość state zwraca bieżący stan zdefiniowany przez CommunicationStatepolecenie :

ICommunicationObject, CommunicationObject i States and State Transition

Element ICommunicationObject rozpoczyna się w stanie Utworzono, w którym można skonfigurować jego różne właściwości. Po otwarciu obiektu można używać do wysyłania i odbierania komunikatów, ale jego właściwości są uznawane za niezmienne. Po przejściu do stanu Zamykanie obiekt nie może już przetwarzać nowych żądań wysyłania lub odbierania, ale istniejące żądania mogą zostać ukończone do momentu osiągnięcia limitu czasu zamknięcia. Jeśli wystąpi nieodwracalny błąd, obiekt przechodzi do stanu Uszkodzony, gdzie można go sprawdzić, aby uzyskać informacje o błędzie i ostatecznie zamknięte. Gdy w stanie Zamknięty obiekt zasadniczo osiągnął koniec maszyny stanu. Gdy obiekt przechodzi z jednego stanu do następnego, nie wraca do poprzedniego stanu.

Na poniższym diagramie przedstawiono ICommunicationObject stany i przejścia stanu. Przejścia stanu mogą być spowodowane wywołaniem jednej z trzech metod: Abort, Open lub Close. Mogą one być również spowodowane wywołaniem innych metod specyficznych dla implementacji. Przejście do stanu Błędy może wystąpić w wyniku błędów podczas otwierania lub po otwarciu obiektu komunikacji.

Każdy ICommunicationObject zaczyna się w stanie Utworzono. W tym stanie aplikacja może skonfigurować obiekt, ustawiając jego właściwości. Gdy obiekt znajduje się w stanie innym niż Utworzono, jest uważany za niezmienny.

Dataflow diagram of the channel state transition.
Rysunek 1. Maszyna stanu ICommunicationObject.

Program Windows Communication Foundation (WCF) udostępnia abstrakcyjną klasę bazową o nazwie CommunicationObject , która implementuje ICommunicationObject i maszynę stanu kanału. Poniższa grafika to zmodyfikowany diagram stanu specyficzny dla CommunicationObjectelementu . Oprócz maszyny ICommunicationObject stanu pokazuje czas wywołania dodatkowych CommunicationObject metod.

Dataflow diagram of CommunicationObject implementation state changes. Rysunek 2. Implementacja obiektu CommunicationObject maszyny stanu ICommunicationObject, w tym wywołania zdarzeń i metod chronionych.

Zdarzenia ICommunicationObject

CommunicationObject uwidacznia pięć zdarzeń zdefiniowanych przez ICommunicationObjectelement . Te zdarzenia są przeznaczone do kodowania przy użyciu obiektu komunikacyjnego, aby otrzymywać powiadomienia o przejściach stanu. Jak pokazano na rysunku 2 powyżej, każde zdarzenie jest uruchamiane raz po przejściu stanu obiektu do stanu nazwanego przez zdarzenie. Wszystkie pięć zdarzeń jest EventHandler typu, który jest zdefiniowany jako:

public delegate void EventHandler(object sender, EventArgs e);

W implementacji CommunicationObject nadawca jest CommunicationObject sam lub jakikolwiek element został przekazany jako nadawca do CommunicationObject konstruktora (jeśli użyto tego przeciążenia konstruktora). Parametr EventArgs, e, jest zawsze EventArgs.Empty.

Wywołania zwrotne obiektów pochodnych

Oprócz pięciu zdarzeń CommunicationObject deklaruje osiem chronionych metod wirtualnych zaprojektowanych w celu umożliwienia wywołania obiektu pochodnego przed przejściem stanu i po nim.

Metody CommunicationObject.Open i CommunicationObject.Close mają trzy takie wywołania zwrotne skojarzone z każdym z nich. Na przykład odpowiadające CommunicationObject.Open istnieją CommunicationObject.OnOpeningwartości , CommunicationObject.OnOpeni CommunicationObject.OnOpened. Skojarzone z CommunicationObject.Close nimi CommunicationObject.OnClosesą metody , CommunicationObject.OnClosingi CommunicationObject.OnClosed .

CommunicationObject.Abort Podobnie metoda ma odpowiedni CommunicationObject.OnAbortelement .

Chociaż CommunicationObject.OnOpen, CommunicationObject.OnClosei CommunicationObject.OnAbort nie mają domyślnej implementacji, inne wywołania zwrotne mają domyślną implementację, która jest niezbędna do poprawności komputera stanu. Jeśli zastąpisz te metody, pamiętaj, aby wywołać implementację podstawową lub poprawnie ją zastąpić.

CommunicationObject.OnOpening, CommunicationObject.OnClosing i CommunicationObject.OnFaulted wyzwol odpowiednie CommunicationObject.Openingzdarzenia i CommunicationObject.ClosingCommunicationObject.Faulted . CommunicationObject.OnOpened i CommunicationObject.OnClosed ustaw odpowiednio stan obiektu na Otwarte i Zamknięte, a następnie uruchom odpowiednie CommunicationObject.Opened zdarzenia i CommunicationObject.Closed .

Metody przejścia stanu

CommunicationObject Zapewnia implementacje abort, Close i Open. Udostępnia również metodę Błąd, która powoduje przejście stanu na stan Uszkodzony. Rysunek 2 przedstawia maszynę ICommunicationObject stanu z każdym przejściem oznaczonym przez metodę, która ją powoduje (przejścia bez etykiet występują wewnątrz implementacji metody, która spowodowała ostatnie przejście oznaczone etykietą).

Uwaga

Wszystkie CommunicationObject implementacje stanu komunikacji pobiera/zestawy są synchronizowane wątkowo.

Konstruktor

CommunicationObject Udostępnia trzy konstruktory, z których wszystkie pozostawiają obiekt w stanie Utworzono. Konstruktory są definiowane jako:

Pierwszy konstruktor jest konstruktorem bez parametrów, który deleguje do przeciążenia konstruktora, który przyjmuje obiekt:

protected CommunicationObject() : this(new object()) { … }

Konstruktor, który przyjmuje obiekt, używa tego parametru jako obiektu do zablokowania podczas synchronizowania dostępu do stanu obiektu komunikacji:

protected CommunicationObject(object mutex) { … }

Na koniec trzeci konstruktor przyjmuje dodatkowy parametr, który jest używany jako argument nadawcy podczas ICommunicationObject wyzwalania zdarzeń.

protected CommunicationObject(object mutex, object eventSender) { … }

Poprzednie dwa konstruktory ustawiły nadawcę na wartość .

Open, metoda

Warunek wstępny: Stan jest tworzony.

Stan po awarii: stan jest otwarty lub uszkodzony. Może zgłosić wyjątek.

Metoda Open() spróbuje otworzyć obiekt komunikacji i ustawić stan na Otwarty. Jeśli wystąpi błąd, zostanie ustawiony stan Na Błąd.

Metoda najpierw sprawdza, czy bieżący stan to Utworzono. Jeśli bieżący stan to Otwarcie lub Otwarte, zgłasza błąd InvalidOperationException. Jeśli bieżący stan to Zamykanie lub Zamykanie CommunicationObjectAbortedException , zgłasza błąd, jeśli obiekt został zakończony i ObjectDisposedException w inny sposób. Jeśli bieżący stan to Błąd, zgłasza błąd CommunicationObjectFaultedException.

Następnie ustawia stan na Otwarcie i wywołuje metodę OnOpening() (która wywołuje zdarzenie otwierające), OnOpen() i OnOpened() w tej kolejności. OnOpened() ustawia stan na Otwarte i wywołuje zdarzenie Otwarte. Jeśli którykolwiek z tych elementów zgłasza wyjątek, funkcja Open()wywołuje metodę Fault() i umożliwia utworzenie bąbelka wyjątku. Na poniższym diagramie przedstawiono bardziej szczegółowy proces Otwierania.

Dataflow diagram of ICommunicationObject.Open state changes.
Zastąpi metodę OnOpen, aby zaimplementować niestandardową otwartą logikę, taką jak otwarcie obiektu komunikacji wewnętrznej.

Close — Metoda

Warunek wstępny: Brak.

Po warunku: stan jest zamknięty. Może zgłosić wyjątek.

Metodę Close() można wywołać w dowolnym stanie. Próbuje zamknąć obiekt normalnie. Jeśli wystąpi błąd, powoduje zakończenie obiektu. Metoda nie wykonuje żadnych czynności, jeśli bieżący stan to Zamykanie lub Zamykanie. W przeciwnym razie ustawia stan na Zamykanie. Jeśli oryginalny stan został utworzony, otwarty lub uszkodzony, wywołuje metodę Abort() (zobacz poniższy diagram). Jeśli oryginalny stan został otwarty, wywołuje onClosing() (co wywołuje zdarzenie zamykające), OnClose() i OnClosed() w tej kolejności. Jeśli którykolwiek z tych elementów zgłasza wyjątek, funkcja Close()wywołuje metodę Abort() i umożliwia bąbelek wyjątku. Wartość OnClosed() ustawia stan Na Zamknięte i zgłasza zdarzenie Zamknięte. Na poniższym diagramie przedstawiono bardziej szczegółowy proces zamykania.

Dataflow diagram of ICommunicationObject.Close state changes.
Zastąpi metodę OnClose, aby zaimplementować niestandardową logikę zamknięcia, taką jak zamknięcie obiektu komunikacji wewnętrznej. Cała bezpieczna logika zamykania, która może blokować przez długi czas (na przykład oczekiwanie na odpowiedź po drugiej stronie), powinna zostać zaimplementowana w elemencie OnClose(), ponieważ wymaga parametru limitu czasu i ponieważ nie jest wywoływana jako część abort().

Przerwij

Warunek wstępny: Brak.
Po warunku: stan jest zamknięty. Może zgłosić wyjątek.

Metoda Abort() nic nie robi, jeśli bieżący stan jest Zamknięty lub jeśli obiekt został zakończony przed (na przykład przez przerwanie() wykonywania w innym wątku. W przeciwnym razie ustawia stan na Zamknięcie i wywołuje metodę OnClosing() (która wywołuje zdarzenie zamykające), OnAbort() i OnClosed() w tej kolejności (nie wywołuje metody OnClose, ponieważ obiekt jest przerywany, a nie zamykany). Wartość OnClosed() ustawia stan Na Zamknięte i zgłasza zdarzenie Zamknięte. Jeśli którykolwiek z tych zgłasza wyjątek, zostanie on ponownie zgłoszony do obiektu wywołującego abort. Implementacje onClosing(), OnClosed() i OnAbort() nie powinny blokować (na przykład w danych wejściowych/wyjściowych). Na poniższym diagramie przedstawiono bardziej szczegółowo proces przerwania.

Dataflow diagram of ICommunicationObject.Abort state changes.
Zastąpi metodę OnAbort w celu zaimplementowania niestandardowej logiki zakończenia, takiej jak zakończenie obiektu komunikacji wewnętrznej.

lokalizator

Metoda Fault jest specyficzna dla CommunicationObject interfejsu i nie jest częścią interfejsu ICommunicationObject . Jest on dołączony tutaj do kompletności.

Warunek wstępny: Brak.

Stan po awarii: Stan jest uszkodzony. Może zgłosić wyjątek.

Metoda Fault() nie wykonuje żadnych operacji, jeśli bieżący stan jest Uszkodzony lub Zamknięty. W przeciwnym razie ustawia stan Na Błąd i wywołaj metodę OnFaulted(), która zgłasza zdarzenie Uszkodzone. Jeśli funkcja OnFaulted zgłasza wyjątek, zostanie on ponownie zgłoszony.

ThrowIfXxx, metody

Obiekt CommunicationObject ma trzy chronione metody, których można użyć do zgłaszania wyjątków, jeśli obiekt jest w określonym stanie.

ThrowIfDisposed zgłasza wyjątek, jeśli stan jest zamykany, zamknięty lub uszkodzony.

ThrowIfDisposedOrImmutable zgłasza wyjątek, jeśli stan nie został utworzony.

ThrowIfDisposedOrNotOpen zgłasza wyjątek, jeśli stan nie jest otwarty.

Zgłoszone wyjątki zależą od stanu. W poniższej tabeli przedstawiono różne stany i odpowiedni typ wyjątku zgłoszony przez wywołanie elementu ThrowIfXxx, który zgłasza ten stan.

Stan Czy abort został wywołany? Wyjątek
Utworzone Nie dotyczy System.InvalidOperationException
Otwieranie Nie dotyczy System.InvalidOperationException
Otwarte Nie dotyczy System.InvalidOperationException
Zamykanie Tak System.ServiceModel.CommunicationObjectAbortedException
Zamykanie Nie. System.ObjectDisposedException
Zamknięcie Tak System.ServiceModel.CommunicationObjectAbortedException w przypadku zamknięcia obiektu przez poprzednie i jawne wywołanie abort. Jeśli wywołasz metodę Close dla obiektu, zostanie zgłoszony element System.ObjectDisposedException .
Zamknięcie Nie. System.ObjectDisposedException
Faulted Nie dotyczy System.ServiceModel.CommunicationObjectFaultedException

Limity czasu

Kilka metod omówionych przez nas parametrów limitu czasu. Są to pozycje Close, Open (niektóre przeciążenia i wersje asynchroniczne), OnClose i OnOpen. Te metody są przeznaczone do zezwalania na długotrwałe operacje (na przykład blokowanie danych wejściowych/wyjściowych podczas bezproblemowego zamykania połączenia), dzięki czemu parametr limitu czasu wskazuje, jak długo takie operacje mogą trwać przed przerwaniem. Implementacje dowolnej z tych metod powinny używać podanej wartości limitu czasu, aby upewnić się, że powraca do obiektu wywołującego w tym przedziale czasu. Implementacje innych metod, które nie zajmują limitu czasu, nie są przeznaczone do długotrwałych operacji i nie powinny blokować danych wejściowych/wyjściowych.

Wyjątkiem są przeciążenia open() i Close(), które nie zajmują limitu czasu. Używają one domyślnej wartości limitu czasu dostarczonej przez klasę pochodną. CommunicationObject Uwidacznia dwie chronione właściwości abstrakcyjne o nazwie DefaultCloseTimeout i DefaultOpenTimeout zdefiniowane jako:

protected abstract TimeSpan DefaultCloseTimeout { get; }

protected abstract TimeSpan DefaultOpenTimeout { get; }

Klasa pochodna implementuje te właściwości, aby zapewnić domyślny limit czasu dla przeciążeń Open() i Close(), które nie zajmują wartości limitu czasu. Następnie implementacje Open() i Close() deleguje do przeciążenia, które trwa przekroczenie limitu czasu, przekazując wartość domyślnego limitu czasu, na przykład:

public void Open()

{

this.Open(this.DefaultOpenTimeout);

}

Idefaultcommunicationtimeouts

Ten interfejs ma cztery właściwości tylko do odczytu zapewniające domyślne wartości limitu czasu otwierania, wysyłania, odbierania i zamykania. Każda implementacja jest odpowiedzialna za uzyskanie wartości domyślnych w dowolny sposób odpowiedni. Dla wygody ChannelFactoryBase i ChannelListenerBase domyślnie te wartości to 1 minuta.