Dela via


Förstå tillståndsändringar

I det här avsnittet beskrivs tillstånd och övergångar som kanaler har, vilka typer som används för att strukturera kanaltillstånd och hur du implementerar dem.

Tillståndsdatorer och kanaler

Objekt som hanterar kommunikation, till exempel sockets, presenterar vanligtvis en tillståndsdator vars tillståndsövergångar avser allokering av nätverksresurser, upprätta eller acceptera anslutningar, stänga anslutningar och avsluta kommunikationen. Kanaltillståndsdatorn tillhandahåller en enhetlig modell av tillstånden för ett kommunikationsobjekt som abstraherar den underliggande implementeringen av objektet. Gränssnittet ICommunicationObject innehåller en uppsättning tillstånd, övergångsmetoder för tillstånd och tillståndsövergångshändelser. Alla kanaler, kanalfabriker och kanallyssnare implementerar kanaltillståndsdatorn.

Händelserna Closed, Closing, Faulted, Opened och Opening signalerar en extern övervakare efter en tillståndsövergång.

Metoderna Abort, Close och Open (och deras asynkrona motsvarigheter) orsakar tillståndsövergångar.

Tillståndsegenskapen returnerar det aktuella tillståndet enligt definitionen av CommunicationState:

ICommunicationObject, CommunicationObject och tillstånd och tillståndsövergång

En ICommunicationObject startar i tillståndet Skapad där dess olika egenskaper kan konfigureras. När objektet är i tillståndet Öppnat kan det användas för att skicka och ta emot meddelanden, men dess egenskaper anses oföränderliga. När objektet är i stängningstillstånd kan det inte längre bearbeta nya skicka eller ta emot begäranden, men befintliga begäranden har en chans att slutföras tills tidsgränsen Stäng har nåtts. Om ett oåterkalleligt fel inträffar övergår objektet till feltillståndet där det kan inspekteras för information om felet och slutligen stängas. När objektet i tillståndet Stängt i princip har nått slutet av tillståndsdatorn. När ett objekt övergår från ett tillstånd till ett annat går det inte tillbaka till ett tidigare tillstånd.

Följande diagram visar tillstånd och ICommunicationObject tillståndsövergångar. Tillståndsövergångar kan orsakas av att någon av de tre metoderna anropas: Avbryt, Öppna eller Stäng. De kan också orsakas av att andra implementeringsspecifika metoder anropas. Övergången till feltillståndet kan inträffa till följd av fel vid öppning eller efter att kommunikationsobjektet har öppnats.

Varje ICommunicationObject startar i tillståndet Skapad. I det här tillståndet kan ett program konfigurera objektet genom att ange dess egenskaper. När ett objekt är i ett annat tillstånd än Skapat anses det oföränderligt.

Dataflow diagram of the channel state transition.
Figur 1. The ICommunicationObject State Machine.

Windows Communication Foundation (WCF) tillhandahåller en abstrakt basklass med namnet CommunicationObject som implementerar ICommunicationObject och kanaltillståndsdatorn. Följande bild är ett ändrat tillståndsdiagram som är specifikt för CommunicationObject. Förutom tillståndsdatorn ICommunicationObject visas tidpunkten när ytterligare CommunicationObject metoder anropas.

Dataflow diagram of CommunicationObject implementation state changes. Bild 2. CommunicationObject-implementeringen av ICommunicationObject-tillståndsdatorn, inklusive anrop till händelser och skyddade metoder.

ICommunicationObject-händelser

CommunicationObject exponerar de fem händelser som definieras av ICommunicationObject. Dessa händelser är utformade för kod som använder kommunikationsobjektet för att meddelas om tillståndsövergångar. Som visas i bild 2 ovan utlöses varje händelse en gång efter att objektets tillstånd övergår till det tillstånd som heter av händelsen. Alla fem händelserna är av den EventHandler typ som definieras som:

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

I implementeringen CommunicationObject är avsändaren antingen CommunicationObject sig själv eller det som skickades som avsändare till CommunicationObject konstruktorn (om konstruktorns överlagring användes). Parametern EventArgs, e, är alltid EventArgs.Empty.

Återanrop till härledda objekt

Utöver de fem händelserna CommunicationObject deklarerar åtta skyddade virtuella metoder som utformats för att tillåta att ett härlett objekt anropas tillbaka före och efter tillståndsövergångar.

Metoderna CommunicationObject.Open och CommunicationObject.Close har tre sådana återanrop associerade med var och en av dem. Till exempel motsvarar CommunicationObject.OpenCommunicationObject.OnOpeningdet , CommunicationObject.OnOpen, och CommunicationObject.OnOpened. Associerade med CommunicationObject.Close är CommunicationObject.OnClosemetoderna , CommunicationObject.OnClosingoch CommunicationObject.OnClosed .

CommunicationObject.Abort På samma sätt har metoden motsvarande CommunicationObject.OnAbort.

Medan CommunicationObject.OnOpen, CommunicationObject.OnCloseoch CommunicationObject.OnAbort inte har någon standardimplementering, har de andra återanropen en standardimplementering som är nödvändig för tillståndsdatorns korrekthet. Om du åsidosätter dessa metoder måste du anropa basimplementeringen eller ersätta den på rätt sätt.

CommunicationObject.OnOpeningoch CommunicationObject.OnClosingCommunicationObject.OnFaulted utlös motsvarande CommunicationObject.Opening, CommunicationObject.Closing och CommunicationObject.Faulted händelser. CommunicationObject.OnOpened och CommunicationObject.OnClosed ange objekttillståndet till Öppnad respektive Stängd och utlös sedan motsvarande CommunicationObject.Opened händelser och CommunicationObject.Closed händelser.

Metoder för tillståndsövergång

CommunicationObject tillhandahåller implementeringar av Abort, Close och Open. Den innehåller också en felmetod som orsakar en tillståndsövergång till feltillståndet. Bild 2 visar ICommunicationObject tillståndsdatorn med varje övergång märkt med den metod som orsakar den (omärkta övergångar sker i implementeringen av metoden som orsakade den senaste märkta övergången).

Kommentar

Alla CommunicationObject implementeringar av kommunikationstillståndet gets/sets är trådsynkronisering.

Konstruktor

CommunicationObject innehåller tre konstruktorer, som alla lämnar objektet i tillståndet Skapad. Konstruktorerna definieras som:

Den första konstruktorn är en parameterlös konstruktor som delegerar till konstruktorns överlagring som tar ett objekt:

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

Konstruktorn som tar ett objekt använder den parametern som det objekt som ska låsas när åtkomsten till kommunikationsobjektets tillstånd synkroniseras:

protected CommunicationObject(object mutex) { … }

Slutligen tar en tredje konstruktor ytterligare en parameter som används som avsändarargument när ICommunicationObject händelser utlöses.

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

De föregående två konstruktorerna anger avsändaren till detta.

Öppna metod

Förutsättning: Tillståndet har skapats.

Eftervillkor: Tillståndet är öppet eller felaktigt. Kan utlösa ett undantag.

Metoden Open() försöker öppna kommunikationsobjektet och ange tillståndet till Öppnat. Om det uppstår ett fel anger det tillståndet till Fel.

Metoden kontrollerar först att det aktuella tillståndet är Skapad. Om det aktuella tillståndet är Öppna eller Öppnade genererar det en InvalidOperationException. Om det aktuella tillståndet är Stängning eller Stängt utlöser det ett CommunicationObjectAbortedException om objektet har avslutats och ObjectDisposedException på annat sätt. Om det aktuella tillståndet är Felat genererar det en CommunicationObjectFaultedException.

Sedan ställs tillståndet in på Öppna och anropar OnOpening() (som genererar öppningshändelsen), OnOpen() och OnOpened() i den ordningen. OnOpened() anger tillståndet till Öppnat och genererar händelsen Öppnade. Om något av dessa utlöser ett undantag anropar Open()Fault() och låter undantaget bubbla upp. I följande diagram visas öppna processen mer detaljerat.

Dataflow diagram of ICommunicationObject.Open state changes.
Åsidosätt metoden OnOpen för att implementera anpassad öppen logik, till exempel att öppna ett inre kommunikationsobjekt.

Stäng-metod

Förhandsvillkor: Ingen.

Eftervillkor: Tillståndet är stängt. Kan utlösa ett undantag.

Metoden Close() kan anropas i valfritt tillstånd. Den försöker stänga objektet normalt. Om ett fel påträffas avslutas objektet. Metoden gör ingenting om det aktuella tillståndet är Stängning eller Stängd. Annars ställs tillståndet in på Stängning. Om det ursprungliga tillståndet har skapats, öppnats eller felats anropas Abort() (se följande diagram). Om det ursprungliga tillståndet öppnades anropas OnClosing() (som genererar händelsen Closing), OnClose() och OnClosed() i den ordningen. Om något av dessa utlöser ett undantag anropar Close()Abort() och låter undantaget bubbla upp. OnClosed() anger tillståndet till Stängd och genererar händelsen Stängd. I följande diagram visas processen Stäng mer i detalj.

Dataflow diagram of ICommunicationObject.Close state changes.
Åsidosätt metoden OnClose för att implementera anpassad stängningslogik, till exempel stänga ett inre kommunikationsobjekt. All graciös stängningslogik som kan blockeras under lång tid (till exempel väntar på att den andra sidan ska svara) ska implementeras i OnClose() eftersom den tar en timeout-parameter och eftersom den inte anropas som en del av Abort().

Avbryt

Förhandsvillkor: Ingen.
Eftervillkor: Tillståndet är stängt. Kan utlösa ett undantag.

Metoden Abort() gör ingenting om det aktuella tillståndet är Stängt eller om objektet har avslutats tidigare (till exempel genom att abort() körs på en annan tråd). I annat fall ställs tillståndet in på Stänga och anropar OnClosing() (som genererar stängningshändelsen), OnAbort() och OnClosed() i den ordningen (anropar inte OnClose eftersom objektet avslutas, inte stängs). OnClosed() anger tillståndet till Stängd och genererar händelsen Stängd. Om något av dessa utlöser ett undantag utlöses det på nytt till anroparen av Abort. Implementeringar av OnClosing(), OnClosed() och OnAbort() bör inte blockera (till exempel på indata/utdata). I följande diagram visas abortprocessen i detalj.

Dataflow diagram of ICommunicationObject.Abort state changes.
Åsidosätt metoden OnAbort för att implementera anpassad avslutningslogik, till exempel att avsluta ett inre kommunikationsobjekt.

Fel

Felmetoden är specifik för CommunicationObject och ingår inte i ICommunicationObject gränssnittet. Det ingår här för fullständighet.

Förhandsvillkor: Ingen.

Eftervillkor: Tillståndet är felaktigt. Kan utlösa ett undantag.

Metoden Fault() gör ingenting om det aktuella tillståndet är Felat eller Stängt. Annars ställs tillståndet in på Fel och anropar OnFaulted(), vilket genererar den felaktiga händelsen. Om OnFaulted utlöser ett undantag utlöses det igen.

ThrowIfXxx-metoder

CommunicationObject har tre skyddade metoder som kan användas för att utlösa undantag om objektet är i ett visst tillstånd.

ThrowIfDisposed genererar ett undantag om tillståndet är Stängning, Stängd eller Fel.

ThrowIfDisposedOrImmutable utlöser ett undantag om tillståndet inte har skapats.

ThrowIfDisposedOrNotOpen utlöser ett undantag om tillståndet inte är Öppnat.

Vilka undantag som utlöses beror på tillståndet. I följande tabell visas de olika tillstånden och motsvarande undantagstyp som genereras genom att anropa en ThrowIfXxx som genererar det tillståndet.

Tillstånd Har Abort anropats? Undantag
Skapad Ej tillämpligt System.InvalidOperationException
Ingående Ej tillämpligt System.InvalidOperationException
Öppnat Ej tillämpligt System.InvalidOperationException
Stänga Ja System.ServiceModel.CommunicationObjectAbortedException
Stänga Nej System.ObjectDisposedException
Stängda Ja System.ServiceModel.CommunicationObjectAbortedException om ett objekt stängdes av ett tidigare och explicit anrop av Abort. Om du anropar Stäng på objektet genereras en System.ObjectDisposedException .
Stängda Nej System.ObjectDisposedException
Fel Ej tillämpligt System.ServiceModel.CommunicationObjectFaultedException

Timeouter

Flera av de metoder som vi diskuterade tar timeout-parametrar. Dessa är Close, Open (vissa överlagringar och asynkrona versioner), OnClose och OnOpen. Dessa metoder är utformade för att tillåta långa åtgärder (till exempel blockering vid indata/utdata samtidigt som en anslutning stängs korrekt) så att timeout-parametern anger hur lång tid sådana åtgärder kan ta innan de avbryts. Implementeringar av någon av dessa metoder bör använda det angivna tidsgränsvärdet för att säkerställa att det återgår till anroparen inom den tidsgränsen. Implementeringar av andra metoder som inte tar en timeout är inte utformade för långa åtgärder och bör inte blockera indata/utdata.

Undantaget är överlagringarna Open() och Close() som inte tar någon timeout. Dessa använder ett standardvärde för timeout som tillhandahålls av den härledda klassen. CommunicationObject exponerar två skyddade abstrakta egenskaper med namnet DefaultCloseTimeout och DefaultOpenTimeout definieras som:

protected abstract TimeSpan DefaultCloseTimeout { get; }

protected abstract TimeSpan DefaultOpenTimeout { get; }

En härledd klass implementerar dessa egenskaper för att ge standardtimeout för överlagringar av Open() och Close() som inte tar ett timeout-värde. Implementeringarna Open() och Close() delegerar sedan till den överlagring som tar en timeout som skickar standardvärdet för timeout, till exempel:

public void Open()

{

this.Open(this.DefaultOpenTimeout);

}

IDefaultCommunicationTimeouts

Det här gränssnittet har fyra skrivskyddade egenskaper för att tillhandahålla standardvärden för timeout för att öppna, skicka, ta emot och stänga. Varje implementering ansvarar för att hämta standardvärdena på det sätt som är lämpligt. Som en bekvämlighet ChannelFactoryBase och ChannelListenerBase standard dessa värden till 1 minut vardera.