Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
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í služby kanálu implementují stavový automat kanálu.
Události Zavřené, Zavírání, Chybné, Otevřené a Otevření signalizují externímu pozorovateli 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 Stavy a Přechod Stavu
ICommunicationObject začíná ve stavu Vytvořeno, 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ý.
Obrázek č. 1. Stavový automat ICommunicationObject.
Windows Communication Foundation (WCF) poskytuje abstraktní základní třídu s názvem CommunicationObject, která implementuje ICommunicationObject a stroj stavů 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.
Obrázek 2 Implementace CommunicationObject stavového stroje ICommunicationObject včetně volání událostí a chráněných metod.
Události objektu ICommunicationObject
CommunicationObject zveř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í derivovaný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.
Metody CommunicationObject.Open a CommunicationObject.Close mají každá tři taková zpětná volání spojená s nimi. Například odpovídající CommunicationObject.Open existuje CommunicationObject.OnOpening, CommunicationObject.OnOpena CommunicationObject.OnOpened. Metody CommunicationObject.Close, CommunicationObject.OnClose a CommunicationObject.OnClosing jsou přidruženy k CommunicationObject.OnClosed.
Podobně metoda CommunicationObject.Abort má 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.OnOpening, CommunicationObject.OnClosing a CommunicationObject.OnFaulted aktivují odpovídající CommunicationObject.Opening, CommunicationObject.Closing 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 pro přerušení, zavření a otevření. 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 získávání/nastavení stavu komunikace jsou synchronizovány mezi vlákny.
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) { … }
Nakonec třetí konstruktor přijímá další parametr, který se použije jako argument odesílatele při vyvolání ICommunicationObject událostí.
protected CommunicationObject(object mutex, object eventSender) { … }
Předchozí dva konstruktory nastavily odesílatele na toto.
Metoda Open
Předběžná podmínka: Stav je vytvořen.
Po splnění podmínky: Stav je otevřen nebo poruchový. 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írání nebo Otevřeno, vyhodí 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 v poruše, vyvolá chybu CommunicationObjectFaultedException.
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řeno a vyvolá událost Otevřeno. Pokud některý z těchto vyvolá výjimku, Open() zavolá Fault() a nechá výjimku projít systémem. Následující diagram znázorňuje podrobněji proces 'Otevřít'.
Přepište metodu OnOpen pro implementaci vlastní otevřené logiky, například otevření vnitřního komunikačního objektu.
Metoda zavření
Předběžná podmínka: Žádná.
Konečný stav: 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 se objeví chyba, objekt se ukončí. Metoda nic nedělá, pokud je aktuální stav Closing nebo Closed. V opačném případě nastaví stav na Závěr. Pokud byl původní stav Vytvořený, Otevírání nebo Porouchaný, 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 uzavření.
Přepište metodu OnClose, aby implementovala vlastní logiku uzavření, jako je například uzavření vnitřního komunikačního objektu. V OnClose() by se měla implementovat veškerá logika hladkého ukončení, která může blokovat dlouhou dobu (například čekání na odpověď druhou stranu), protože má parametr časového limitu a neboť není volána v rámci Abort().
Zrušit
Předběžná podmínka: Žádná.
Konečný stav: Stav je uzavřen. Může vyvolat výjimku.
Metoda Abort() nedělá nic, pokud aktuální stav je Uzavřeno nebo pokud byl objekt ukončen předtím (například spuštění Abort() na jiném vlákně). V opačném případě nastaví stav na Closing a volá funkce OnClosing() (což vyvolá událost Closing), OnAbort() a OnClosed() v daném pořadí (nevolá 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 nich vyvolá výjimku, je znovu vyvolána volajícímu funkce Abort. 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.
Přepište metodu OnAbort k implementaci vlastní logiky ukončení, jako je například ukončení vnitřního komunikačního objektu.
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 chybný a volá OnFaulted(), což vyvolá událost Faulted. Pokud OnFaulted vyvolá výjimku, je tato výjimka 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.
| Stát | Bylo voláno přerušení? | Výjimka |
|---|---|---|
| Vytvořeno | není k dispozici | System.InvalidOperationException |
| Otevření | není k dispozici | System.InvalidOperationException |
| Otevřeno | není k dispozici | System.InvalidOperationException |
| Uzavření | Ano | System.ServiceModel.CommunicationObjectAbortedException |
| Uzavření | Ne | 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 metodu Close na objektu, je vyvolána System.ObjectDisposedException. |
| Zavřeno | Ne | System.ObjectDisposedException |
| S chybou | není k dispozici | System.ServiceModel.CommunicationObjectFaultedException |
Časové limity
Řada metod, které jsme probrali, používá 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á nevyžadují č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á nepřijímají hodnotu časového limitu. Poté implementace metod Open() a Close() delegují na přetížení, které přijímá časový limit jako argument, a předává jí 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 odpovídajícím způsobem. Pro zjednodušení ChannelFactoryBase a ChannelListenerBase nastaví výchozí hodnoty na 1 minutu pro každou.