Delen via


Statuswijzigingen begrijpen

In dit onderwerp worden de statussen en overgangen besproken die kanalen hebben, de typen die worden gebruikt om kanaalstatussen te structureren en hoe u deze implementeert.

Statusmachines en kanalen

Objecten die omgaan met communicatie, bijvoorbeeld sockets, presenteren meestal een statusmachine waarvan de statusovergangen betrekking hebben op het toewijzen van netwerkbronnen, het maken of accepteren van verbindingen, het sluiten van verbindingen en het beëindigen van communicatie. De kanaalstatusmachine biedt een uniform model van de statussen van een communicatieobject waarmee de onderliggende implementatie van dat object wordt geabstraheerd. De ICommunicationObject interface biedt een set statusovergangsmethoden en statusovergangsevenementen. Alle kanalen, kanaalfactory's en kanaallisteners implementeren de kanaalstatusmachine.

De gebeurtenissen Gesloten, Sluiten, Mislukt, Geopend en Openen geven een externe waarnemer aan nadat een statusovergang heeft plaatsgevonden.

De methoden afbreken, sluiten en openen (en hun asynchrone equivalenten) veroorzaken statusovergangen.

De statuseigenschap retourneert de huidige status zoals gedefinieerd door CommunicationState:

ICommunicationObject, CommunicationObject en State Transition

Een ICommunicationObject begint in de status Gemaakt waar de verschillende eigenschappen kunnen worden geconfigureerd. Eenmaal in de status Geopend is het object bruikbaar voor het verzenden en ontvangen van berichten, maar de eigenschappen ervan worden als onveranderbaar beschouwd. Zodra de status Sluiten is bereikt, kan het object geen nieuwe verzend- of ontvangstaanvragen meer verwerken, maar bestaande aanvragen hebben de kans om te voltooien totdat de time-out Sluiten is bereikt. Als er een onherstelbare fout optreedt, wordt het object overgezet naar de status Defect, waar deze kan worden gecontroleerd op informatie over de fout en uiteindelijk gesloten. Wanneer het object de status Gesloten heeft, heeft het object het einde van de statusmachine bereikt. Zodra een object van de ene status naar de volgende overgaat, gaat het niet terug naar een eerdere status.

In het volgende diagram ziet u de ICommunicationObject statussen en statusovergangen. Statusovergangen kunnen worden veroorzaakt door een van de drie methoden aan te roepen: Afbreken, Openen of Sluiten. Ze kunnen ook worden veroorzaakt door het aanroepen van andere implementatiespecifieke methoden. De overgang naar de status Fout kan optreden als gevolg van fouten tijdens het openen of nadat het communicatieobject is geopend.

Elke ICommunicationObject start in de status Gemaakt. In deze status kan een toepassing het object configureren door de eigenschappen ervan in te stellen. Zodra een object een andere status heeft dan Gemaakt, wordt het beschouwd als onveranderbaar.

Dataflow diagram of the channel state transition.
Figuur 1. De ICommunicationObject State Machine.

Windows Communication Foundation (WCF) biedt een abstracte basisklasse met de naam CommunicationObject die wordt geïmplementeerd ICommunicationObject en de machine met de kanaalstatus. De volgende afbeelding is een aangepast statusdiagram dat specifiek is voor CommunicationObject. Naast de ICommunicationObject statusmachine wordt de timing weergegeven wanneer extra CommunicationObject methoden worden aangeroepen.

Dataflow diagram of CommunicationObject implementation state changes. Afbeelding 2. De CommunicationObject-implementatie van de ICommunicationObject-statuscomputer, inclusief aanroepen naar gebeurtenissen en beveiligde methoden.

Gebeurtenissen ICommunicationObject

CommunicationObject toont de vijf gebeurtenissen die zijn gedefinieerd door ICommunicationObject. Deze gebeurtenissen zijn ontworpen voor code die het communicatieobject gebruikt om op de hoogte te worden gesteld van statusovergangen. Zoals weergegeven in afbeelding 2 hierboven, wordt elke gebeurtenis eenmaal geactiveerd nadat de status van het object is overgestapt op de status die door de gebeurtenis wordt genoemd. Alle vijf gebeurtenissen zijn van het EventHandler type dat wordt gedefinieerd als:

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

In de CommunicationObject implementatie is de afzender het CommunicationObject zelf of wat er als afzender aan de CommunicationObject constructor is doorgegeven (als die constructoroverbelasting is gebruikt). De parameter EventArgs, eis altijd EventArgs.Empty.

Callbacks voor afgeleide objecten

Naast de vijf gebeurtenissen CommunicationObject declareert u acht beveiligde virtuele methoden die zijn ontworpen om een afgeleid object weer aan te roepen voor en na statusovergangen.

Aan de CommunicationObject.Open en CommunicationObject.Close methoden zijn drie dergelijke callbacks gekoppeld. Zo zijn CommunicationObject.OpenCommunicationObject.OnOpeninger bijvoorbeeld , CommunicationObject.OnOpenen CommunicationObject.OnOpened. CommunicationObject.Close Gekoppeld zijn de CommunicationObject.OnClose, CommunicationObject.OnClosingen CommunicationObject.OnClosed methoden.

Op dezelfde manier heeft de CommunicationObject.Abort methode een bijbehorende CommunicationObject.OnAbort.

Hoewel CommunicationObject.OnOpen, CommunicationObject.OnCloseen CommunicationObject.OnAbort geen standaard-implementatie hebben, hebben de andere callbacks een standaard-implementatie die nodig is voor de juistheid van de statuscomputer. Als u deze methoden overschrijft, moet u de basis-implementatie aanroepen of deze correct vervangen.

CommunicationObject.OnOpening, CommunicationObject.OnClosing en CommunicationObject.OnFaulted de bijbehorende CommunicationObject.Opening, CommunicationObject.Closing en CommunicationObject.Faulted gebeurtenissen te activeren. CommunicationObject.OnOpened en CommunicationObject.OnClosed stel de objectstatus respectievelijk geopend en gesloten in en open vervolgens de bijbehorende CommunicationObject.Opened gebeurtenissen CommunicationObject.Closed .

Statusovergangsmethoden

CommunicationObject biedt implementaties van Afbreken, Sluiten en Openen. Het biedt ook een foutmethode die een statusovergang naar de status Mislukt veroorzaakt. Afbeelding 2 toont de ICommunicationObject statusmachine met elke overgang die is gelabeld door de methode die deze veroorzaakt (niet-gelabelde overgangen vinden plaats in de implementatie van de methode die de laatste gelabelde overgang heeft veroorzaakt).

Notitie

Alle CommunicationObject implementaties van communicatiestatussen worden gesynchroniseerd met threads.

Constructor

CommunicationObject biedt drie constructors, die allemaal het object in de status Gemaakt verlaten. De constructors worden gedefinieerd als:

De eerste constructor is een parameterloze constructor die delegert aan de overbelasting van de constructor die een object gebruikt:

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

De constructor die een object gebruikt, gebruikt die parameter als het object dat moet worden vergrendeld bij het synchroniseren van de toegang tot de status van het communicatieobject:

protected CommunicationObject(object mutex) { … }

Ten slotte gebruikt een derde constructor een extra parameter die wordt gebruikt als het argument afzender wanneer ICommunicationObject gebeurtenissen worden geactiveerd.

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

De vorige twee constructors stellen de afzender in op dit.

Open-methode

Voorwaarde: Staat wordt gemaakt.

Na de voorwaarde: status is geopend of mislukt. Kan een uitzondering genereren.

Met de methode Open() wordt geprobeerd het communicatieobject te openen en de status in te stellen op Openen. Als er een fout optreedt, wordt de status ingesteld op Mislukt.

De methode controleert eerst of de huidige status is gemaakt. Als de huidige status Openen of Openen is, werpt deze een InvalidOperationException. Als de huidige status Sluiten of Gesloten is, wordt er een CommunicationObjectAbortedException gegenereerd als het object is beëindigd en ObjectDisposedException anders. Als de huidige status defect is, wordt er een CommunicationObjectFaultedException.

Vervolgens wordt de status ingesteld op Openen en wordt OnOpening() aanroepen (waardoor de gebeurtenis Openen wordt gegenereerd), OnOpen() en OnOpened() in die volgorde. OnOpened() stelt de status in op Openen en genereert de gebeurtenis Geopend. Als een van deze een uitzondering genereert, roept Open()fault() aan en laat de uitzondering opbellen. In het volgende diagram ziet u het proces Openen in meer detail.

Dataflow diagram of ICommunicationObject.Open state changes.
Overschrijf de methode OnOpen om aangepaste open logica te implementeren, zoals het openen van een binnenste communicatieobject.

Methode Sluiten

Voorwaarde: Geen.

Na de voorwaarde: status is gesloten. Kan een uitzondering genereren.

De methode Close() kan op elke status worden aangeroepen. Er wordt geprobeerd het object normaal te sluiten. Als er een fout optreedt, wordt het object beëindigd. De methode doet niets als de huidige status Sluiten of Gesloten is. Anders wordt de status ingesteld op Sluiten. Als de oorspronkelijke staat is gemaakt, geopend of mislukt, wordt Abort() aangeroepen (zie het volgende diagram). Als de oorspronkelijke staat is geopend, wordt OnClosing() aangeroepen (waardoor de afsluitgebeurtenis wordt gegenereerd), OnClose() en OnClosed() in die volgorde. Als een van deze een uitzondering genereert, roept Close()aan Abort() aan en kan de uitzondering opbellen. OnClosed() stelt de status in op Gesloten en genereert de gebeurtenis Gesloten. In het volgende diagram ziet u het proces Sluiten in meer detail.

Dataflow diagram of ICommunicationObject.Close state changes.
Overschrijf de methode OnClose om aangepaste sluitlogica te implementeren, zoals het sluiten van een inner communication-object. Alle sierlijke afsluitlogica die lange tijd kan blokkeren (bijvoorbeeld wachten totdat de andere kant reageert) moet worden geïmplementeerd in OnClose() omdat er een time-outparameter nodig is en omdat deze niet wordt aangeroepen als onderdeel van Abort().

Afbreken

Voorwaarde: Geen.
Na de voorwaarde: status is gesloten. Kan een uitzondering genereren.

De methode Abort() doet niets als de huidige status gesloten is of als het object eerder is beëindigd (bijvoorbeeld door Abort() uit te voeren op een andere thread. Anders wordt de status ingesteld op Sluiten en wordt OnClosing() aangeroepen (waardoor de gebeurtenis Sluiten wordt gegenereerd), OnAbort() en OnClosed() in die volgorde (wordt OnClose niet aangeroepen omdat het object wordt beëindigd, niet gesloten). OnClosed() stelt de status in op Gesloten en genereert de gebeurtenis Gesloten. Als een van deze een uitzondering genereert, wordt deze opnieuw gegenereerd aan de beller van Abort. Implementaties van OnClosing(), OnClosed() en OnAbort() mogen niet worden geblokkeerd (bijvoorbeeld bij invoer/uitvoer). In het volgende diagram ziet u het proces afbreken in meer detail.

Dataflow diagram of ICommunicationObject.Abort state changes.
Overschrijf de OnAbort-methode om aangepaste beëindigingslogica te implementeren, zoals het beëindigen van een inner communication-object.

Probleem

De foutmethode is specifiek voor CommunicationObject en maakt geen deel uit van de ICommunicationObject interface. Het is hier opgenomen voor volledigheid.

Voorwaarde: Geen.

Na de voorwaarde: status is mislukt. Kan een uitzondering genereren.

De methode Fault() doet niets als de huidige status is verbroken of gesloten. Anders wordt de status ingesteld op Defect en roept u OnFaulted() aan, waardoor de foutieve gebeurtenis wordt gegenereerd. Als OnFaulted een uitzondering genereert, wordt deze opnieuw gegenereerd.

ThrowIfXxx-methoden

CommunicationObject heeft drie beveiligde methoden die kunnen worden gebruikt om uitzonderingen te genereren als het object een specifieke status heeft.

ThrowIfDisposed genereert een uitzondering als de status Sluiten, Gesloten of Mislukt is.

ThrowIfDisposedOrImmutable genereert een uitzondering als de status niet is gemaakt.

ThrowIfDisposedOrNotOpen genereert een uitzondering als de status niet is geopend.

De uitzonderingen die worden gegenereerd, zijn afhankelijk van de status. In de volgende tabel ziet u de verschillende statussen en het bijbehorende uitzonderingstype dat wordt gegenereerd door een ThrowIfXxx aan te roepen die op die status wordt gegenereerd.

Provincie Is Abort gebeld? Uitzondering
Gemaakt N.v.t. System.InvalidOperationException
Opening N.v.t. System.InvalidOperationException
Geopend N.v.t. System.InvalidOperationException
Sluiten Ja System.ServiceModel.CommunicationObjectAbortedException
Sluiten Nee System.ObjectDisposedException
Gesloten Ja System.ServiceModel.CommunicationObjectAbortedException in het geval dat een object is gesloten door een eerdere en expliciete aanroep van Abort. Als u Close op het object aanroept, wordt er een System.ObjectDisposedException gegenereerd.
Gesloten Nee System.ObjectDisposedException
Fout opgetreden N.v.t. System.ServiceModel.CommunicationObjectFaultedException

Time-outs

Verschillende methoden die we hebben besproken, hebben time-outparameters voor take-outs besproken. Dit zijn Sluiten, Openen (bepaalde overbelastingen en asynchrone versies), OnClose en OnOpen. Deze methoden zijn ontworpen om langdurige bewerkingen toe te staan (bijvoorbeeld blokkeren van invoer/uitvoer terwijl een verbinding correct wordt afgesloten), zodat de time-outparameter aangeeft hoe lang dergelijke bewerkingen kunnen duren voordat ze worden onderbroken. Implementaties van een van deze methoden moeten gebruikmaken van de opgegeven time-outwaarde om ervoor te zorgen dat deze binnen die time-out terugkeert naar de aanroeper. Implementaties van andere methoden die geen time-out nemen, zijn niet ontworpen voor langdurige bewerkingen en mogen niet blokkeren voor invoer/uitvoer.

De uitzondering hierop zijn de overbelastingen Open() en Close() die geen time-out in beslag nemen. Deze gebruiken een standaardtime-outwaarde die wordt geleverd door de afgeleide klasse. CommunicationObject maakt twee beveiligde abstracte eigenschappen beschikbaar met de naam DefaultCloseTimeout en DefaultOpenTimeout gedefinieerd als:

protected abstract TimeSpan DefaultCloseTimeout { get; }

protected abstract TimeSpan DefaultOpenTimeout { get; }

Een afgeleide klasse implementeert deze eigenschappen om de standaardtime-out te bieden voor de overbelastingen Open() en Close() die geen time-outwaarde innemen. Vervolgens delegeren de implementaties Open() en Close() aan de overbelasting waarvoor een time-out nodig is, waarbij deze de standaardtime-outwaarde doorgeeft, bijvoorbeeld:

public void Open()

{

this.Open(this.DefaultOpenTimeout);

}

IDefaultCommunicationTimeouts

Deze interface heeft vier alleen-lezen eigenschappen voor het bieden van standaardtime-outwaarden voor openen, verzenden, ontvangen en sluiten. Elke implementatie is verantwoordelijk voor het verkrijgen van de standaardwaarden op welke manier dan ook. Deze waarden worden standaard ChannelFactoryBaseChannelListenerBase ingesteld op 1 minuut.