Sdílet prostřednictvím


Principy změn stavů

Toto téma popisuje stavy a přechody, které kanály mají, typy používané ke strukturování stavů kanálů a jejich implementaci.

Stavové počítače a kanály

Objekty, které se zabývají komunikací, například sokety, obvykle představují stavový počítač, jehož přechody stavu se týkají přidělování síťových prostředků, vytváření nebo přijímání připojení, uzavření připojení a ukončení komunikace. Stavový stroj kanálu poskytuje jednotný model stavů komunikačního objektu, který abstrahuje základní implementaci tohoto objektu. Rozhraní ICommunicationObject poskytuje sadu stavů, metod přechodu stavu a události přechodu stavu. Všechny kanály, továrny kanálů a naslouchací procesy kanálu implementují stavový počítač kanálu.

Události Zavřené, Zavřené, Chybné, Otevřené a Otevření signálu externí pozorovatel po přechodu stavu.

Metody Abort, Close a Open (a jejich asynchronní ekvivalenty) způsobují přechody stavu.

Vlastnost state vrátí aktuální stav definovaný CommunicationState:

ICommunicationObject, CommunicationObject a State Transition

Spustí ICommunicationObject se ve stavu Vytvoření, kde je možné konfigurovat různé vlastnosti. Jakmile je v otevřeném stavu, objekt je použitelný pro odesílání a přijímání zpráv, ale jeho vlastnosti jsou považovány za neměnné. Jakmile je objekt ve stavu Uzavření, nemůže již zpracovávat nové požadavky pro odesílání nebo přijímání, ale stávající požadavky mají šanci dokončit, dokud nebude dosaženo časového limitu uzavření. Pokud dojde k neopravitelné chybě, objekt přejde do chybného stavu, kde je možné zkontrolovat informace o chybě a nakonec zavřít. Když v zavřeném stavu objekt v podstatě dosáhl konce stavového počítače. Jakmile objekt přejde z jednoho stavu na druhý, nepřejde zpět do předchozího stavu.

Následující diagram znázorňuje ICommunicationObject stavy a přechody stavu. Přechody stavu můžou být způsobeny voláním jedné ze tří metod: přerušení, otevření nebo zavření. Mohou být také způsobeny voláním jiných metod specifických pro implementaci. Přechod na chybný stav může nastat v důsledku chyb při otevření nebo po otevření komunikačního objektu.

Každá ICommunicationObject začíná ve stavu Vytvoření. V tomto stavu může aplikace nakonfigurovat objekt nastavením jeho vlastností. Jakmile je objekt v jiném stavu než Vytvořený, považuje se za neměnný.

Dataflow diagram of the channel state transition.
Obrázek č. 1. The ICommunicationObject State Machine.

Windows Communication Foundation (WCF) poskytuje abstraktní základní třídu s názvem CommunicationObject implementuje ICommunicationObject a stavový počítač kanálu. Následující obrázek je upravený stavový diagram, který je specifický pro CommunicationObject. Kromě stavového ICommunicationObject počítače zobrazuje časování při vyvolání dalších CommunicationObject metod.

Dataflow diagram of CommunicationObject implementation state changes. Obrázek 2 Implementace CommunicationObject stavového počítače ICommunicationObject včetně volání událostí a chráněných metod.

Události objektu ICommunicationObject

CommunicationObjectzveřejňuje pět událostí definovaných .ICommunicationObject Tyto události jsou určené pro kód, který používá komunikační objekt, který má být upozorněn na přechody stavu. Jak je znázorněno na obrázku 2 výše, každá událost se aktivuje jednou po přechodu stavu objektu na stav pojmenovaný událostí. Všech pět událostí je typu EventHandler , který je definován jako:

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

CommunicationObject V implementaci je odesílatel buď CommunicationObject sám, nebo cokoli bylo předáno jako odesílatel CommunicationObject konstruktoru (pokud bylo použito přetížení konstruktoru). Parametr EventArgs je evždy EventArgs.Empty.

Zpětná volání odvozených objektů

Kromě pěti událostí deklaruje osm chráněných virtuálních metod navržených tak, CommunicationObject aby bylo možné odvozený objekt volat zpět před přechody stavu a po nich.

Tyto CommunicationObject.Open metody CommunicationObject.Close mají tři takové zpětné volání spojené s každou z nich. Například odpovídající CommunicationObject.Open existuje CommunicationObject.OnOpening, CommunicationObject.OnOpena CommunicationObject.OnOpened. CommunicationObject.Close Přidruženy CommunicationObject.OnClosejsou , CommunicationObject.OnClosinga CommunicationObject.OnClosed metody.

Podobně má CommunicationObject.Abort metoda odpovídající CommunicationObject.OnAbort.

Zatímco CommunicationObject.OnOpen, CommunicationObject.OnClosea CommunicationObject.OnAbort nemají žádnou výchozí implementaci, ostatní zpětná volání mají výchozí implementaci, která je nezbytná pro správnost stavového počítače. Pokud tyto metody přepíšete, nezapomeňte volat základní implementaci nebo ji správně nahradit.

CommunicationObject.OnOpeningCommunicationObject.OnClosing a CommunicationObject.OnFaulted aktivujte odpovídající CommunicationObject.ClosingCommunicationObject.Openingudálosti a CommunicationObject.Faulted události. CommunicationObject.OnOpened a CommunicationObject.OnClosed nastavte stav objektu na Otevřeno a Uzavřeno potom aktivujte odpovídající CommunicationObject.Opened a CommunicationObject.Closed události.

Metody přechodu stavu

CommunicationObject poskytuje implementace Abort, Close a Open. Poskytuje také metodu Fault, která způsobuje přechod stavu na chybný stav. Obrázek 2 znázorňuje stavový ICommunicationObject počítač s jednotlivými přechody označenými metodou, která ho způsobí (neoznačené přechody probíhají uvnitř implementace metody, která způsobila poslední označený přechod).

Poznámka:

Všechny CommunicationObject implementace stavu komunikace načte/sady jsou synchronizované z více vláken.

Konstruktor

CommunicationObject poskytuje tři konstruktory, z nichž všechny opouštějí objekt ve stavu Vytvoření. Konstruktory jsou definovány takto:

První konstruktor je konstruktor bez parametrů, který deleguje na přetížení konstruktoru, který přebírá objekt:

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

Konstruktor, který přebírá objekt, používá tento parametr jako objekt, který má být uzamčen při synchronizaci přístupu ke stavu komunikačního objektu:

protected CommunicationObject(object mutex) { … }

Třetí konstruktor nakonec vezme další parametr, který se použije jako argument odesílatele při ICommunicationObject vyvolání událostí.

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

Předchozí dva konstruktory nastavily odesílatele na toto.

Open – metoda

Předběžná podmínka: Stav je vytvořen.

Po podmínce: Stav je otevřen nebo je chybný. Může vyvolat výjimku.

Metoda Open() se pokusí otevřít komunikační objekt a nastavit stav Otevřený. Pokud dojde k chybě, nastaví se stav Chybný.

Metoda nejprve zkontroluje, zda je aktuální stav vytvořen. Pokud je aktuální stav Otevření nebo Otevřen, vyvolá výjimku InvalidOperationException. Pokud je aktuální stav Zavřený nebo Uzavřeno, vyvolá CommunicationObjectAbortedException chybu, pokud byl objekt ukončen a ObjectDisposedException jinak. Pokud je aktuální stav Chybný, vyvolá CommunicationObjectFaultedExceptionchybu .

Potom nastaví stav Na Otevření a zavolá OnOpening() (což vyvolá událost Otevření), OnOpen() a OnOpened() v daném pořadí. OnOpened() nastaví stav Na Otevření a vyvolá událost Otevření. Pokud některý z těchto vyvolá výjimku, Open()zavolá Fault() a nechá výjimku bublinu nahoru. Následující diagram znázorňuje podrobněji proces Otevřít.

Dataflow diagram of ICommunicationObject.Open state changes.
Přepište metodu OnOpen pro implementaci vlastní otevřené logiky, například otevření vnitřního komunikačního objektu.

Close – metoda

Předběžná podmínka: Žádná.

Po podmínce: Stav je uzavřen. Může vyvolat výjimku.

Metodu Close() lze volat v libovolném stavu. Pokusí se objekt normálně zavřít. Pokud dojde k chybě, objekt se ukončí. Metoda nedělá nic, pokud aktuální stav je Closing nebo Closed. V opačném případě nastaví stav na Závěr. Pokud byl původní stav vytvořen, otevírá nebo chybován, volá Abort() (viz následující diagram). Pokud byl původní stav Otevřen, volá OnClosing() (což vyvolá uzavírací událost), OnClose() a OnClosed() v daném pořadí. Pokud některý z těchto vyvolá výjimku, Close()volá Abort() a nechá bublinu výjimky nahoru. OnClosed() nastaví stav na Uzavřeno a vyvolá uzavřenou událost. Následující diagram znázorňuje podrobněji proces Zavřít.

Dataflow diagram of ICommunicationObject.Close state changes.
Přepsat OnClose metoda implementovat vlastní zavření logiky, jako je například uzavření vnitřní komunikační objekt. V OnClose() by se měla implementovat veškerá logika odkladu, která může blokovat dlouhou dobu (například čekání na odpověď na druhou stranu), protože trvá parametr časového limitu a protože není volána jako součást Abort().

Přerušit

Předběžná podmínka: Žádná.
Po podmínce: Stav je uzavřen. Může vyvolat výjimku.

Metoda Abort() nedělá nic, pokud je aktuální stav Uzavřeno nebo pokud byl objekt ukončen dříve (například pomocí Abort() spuštěna v jiném vlákně). V opačném případě nastaví stav Na Closing a volá OnClosing() (což vyvolává uzavírací událost), OnAbort() a OnClosed() v daném pořadí (nevyvolá OnClose, protože objekt je ukončen, není uzavřen). OnClosed() nastaví stav na Uzavřeno a vyvolá uzavřenou událost. Pokud některý z těchto vyvolá výjimku, vyvolá se volajícímu přerušení znovu. Implementace OnClosing(), OnClosed() a OnAbort() by neměly blokovat (například u vstupu a výstupu). Následující diagram znázorňuje proces přerušení podrobněji.

Dataflow diagram of ICommunicationObject.Abort state changes.
Přepsat OnAbort metoda implementovat vlastní ukončovací logiku, jako je ukončení vnitřní komunikační objekt.

Chyba

Metoda Fault je specifická pro CommunicationObject rozhraní a není součástí ICommunicationObject rozhraní. Je zde zahrnuta pro úplnost.

Předběžná podmínka: Žádná.

Po podmínce: Stav je chybný. Může vyvolat výjimku.

Metoda Fault() nedělá nic, pokud je aktuální stav Chyba nebo Uzavřeno. V opačném případě nastaví stav Na selhání a volání OnFaulted(), což vyvolá chybnou událost. Pokud OnFaulted vyvolá výjimku, je znovu vyvolána.

ThrowIfXxx – metody

CommunicationObject má tři chráněné metody, které lze použít k vyvolání výjimek, pokud je objekt v určitém stavu.

ThrowIfDisposed vyvolá výjimku, pokud je stav zavřený, uzavřený nebo chybný.

ThrowIfDisposedOrImmutable vyvolá výjimku, pokud stav není vytvořen.

ThrowIfDisposedOrNotOpen vyvolá výjimku, pokud stav není otevřen.

Vyvolané výjimky závisí na stavu. Následující tabulka ukazuje různé stavy a odpovídající typ výjimky vyvolaný voláním ThrowIfXxx, který vyvolá tento stav.

Stav Byl volána Abortová? Výjimka
Vytvořeno System.InvalidOperationException
Otevření System.InvalidOperationException
Otevřeno System.InvalidOperationException
Zavření Ano System.ServiceModel.CommunicationObjectAbortedException
Zavření No System.ObjectDisposedException
Zavřeno Ano System.ServiceModel.CommunicationObjectAbortedException v případě, že objekt byl uzavřen předchozím a explicitním voláním Abort. Pokud zavoláte zavřít objektu, vyvolá se vyvolán System.ObjectDisposedException .
Zavřeno No System.ObjectDisposedException
Došlo k chybě System.ServiceModel.CommunicationObjectFaultedException

Časové limity

Několik metod, které jsme probrali, trvá parametry časového limitu. Jedná se o close, Open (určitá přetížení a asynchronní verze), OnClose a OnOpen. Tyto metody jsou navržené tak, aby umožňovaly zdlouhavé operace (například blokování vstupu a výstupu při řádném zavření připojení), aby parametr časového limitu indikoval, jak dlouho tyto operace mohou před přerušením trvat. Implementace některé z těchto metod by měly použít zadanou hodnotu časového limitu, aby se v rámci tohoto časového limitu vrátila volajícímu. Implementace jiných metod, které nezabírají časový limit, nejsou určeny pro zdlouhavé operace a neměly by blokovat vstup/výstup.

Výjimkou jsou přetížení Open() a Close(), která nezabírají časový limit. Tyto používají výchozí hodnotu časového limitu zadanou odvozenou třídou. CommunicationObject zveřejňuje dvě chráněné abstraktní vlastnosti pojmenované DefaultCloseTimeout a DefaultOpenTimeout definované takto:

protected abstract TimeSpan DefaultCloseTimeout { get; }

protected abstract TimeSpan DefaultOpenTimeout { get; }

Odvozená třída implementuje tyto vlastnosti za účelem poskytnutí výchozího časového limitu pro přetížení Open() a Close(), které nezabírají hodnotu časového limitu. Potom implementace Open() a Close() delegují na přetížení, které trvá vypršení časového limitu, který jí předá výchozí hodnotu časového limitu, například:

public void Open()

{

this.Open(this.DefaultOpenTimeout);

}

IDefaultCommunicationTimeouts

Toto rozhraní má čtyři vlastnosti jen pro čtení pro poskytnutí výchozích hodnot časového limitu pro otevření, odesílání, přijímání a zavření. Každá implementace je zodpovědná za získání výchozích hodnot jakýmkoli způsobem odpovídajícím způsobem. Jako pohodlí ChannelFactoryBase a ChannelListenerBase výchozí hodnoty na 1 minutu.