Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Cette rubrique décrit les états et les transitions dont disposent les canaux, les types utilisés pour structurer les états de canal et comment les implémenter.
Ordinateurs et canaux d’état
Les objets qui traitent de la communication, par exemple les sockets, présentent généralement un ordinateur d’état dont les transitions d’état sont liées à l’allocation de ressources réseau, à l’établissement ou à l’acceptation de connexions, à la fermeture des connexions et à la fin de la communication. L’ordinateur d’état du canal fournit un modèle uniforme des états d’un objet de communication qui extrait l’implémentation sous-jacente de cet objet. L’interface ICommunicationObject fournit un ensemble d’états, de méthodes de transition d’état et d’événements de transition d’état. Tous les canaux, toutes les fabrications de canaux et tous les écouteurs de canal implémentent l'ordinateur d'état des canaux.
Les événements Closed, Closing, Faulted, Opened et Opening avertissent un observateur externe après une transition d'état.
Les méthodes Abort, Close et Open (et leurs équivalents asynchrones) entraînent des transitions d’état.
La propriété d'état retourne l'état actuel comme le définit CommunicationState :
ICommunicationObject, CommunicationObject et États et Transition d’état
Un ICommunicationObject commence dans l'état créé où ses différentes propriétés peuvent être configurées. Une fois dans l’état Ouvert, l’objet est utilisable pour l’envoi et la réception de messages, mais ses propriétés sont considérées comme immuables. Une fois dans l’état De fermeture, l’objet ne peut plus traiter de nouvelles demandes d’envoi ou de réception, mais les requêtes existantes ont la possibilité de se terminer jusqu’à ce que le délai d’expiration de fermeture soit atteint. Si une erreur irrécupérable se produit, l’objet passe à l’état d’erreur où il peut être inspecté pour obtenir des informations sur l’erreur et finalement fermé. Lorsque l'objet est dans l'état Fermé, il a essentiellement atteint la fin de la machine à états. Une fois qu’un objet passe d’un état à l’autre, il ne revient pas à un état précédent.
Le diagramme suivant montre les ICommunicationObject états et les transitions d’état. Les transitions d’état peuvent être provoquées par l’appel de l’une des trois méthodes suivantes : Abort, Open ou Close. Elles peuvent également être provoquées par l’appel d’autres méthodes spécifiques à l’implémentation. La transition vers l’état défectueux peut se produire en raison d’erreurs lors de l’ouverture ou après avoir ouvert l’objet de communication.
Chaque ICommunicationObject démarre dans l'état Created. Dans cet état, une application peut configurer l’objet en définissant ses propriétés. Une fois qu’un objet est dans un état autre que Created, il est considéré comme immuable.
Figure 1. La Machine à états ICommunicationObject.
Windows Communication Foundation (WCF) fournit une classe de base abstraite nommée CommunicationObject qui implémente ICommunicationObject et l’ordinateur d’état du canal. Le graphique suivant est un diagramme d’état modifié spécifique à CommunicationObject. Outre l'ordinateur d'état ICommunicationObject, il présente la temporisation lorsque des méthodes CommunicationObject supplémentaires sont appelées.
Figure 2. Implémentation CommunicationObject de l'ordinateur d'état ICommunicationObject comprenant les appels d'événements et de méthodes protégées.
Événements ICommunicationObject
CommunicationObject expose les cinq événements définis par ICommunicationObject. Ces événements sont conçus pour que le code utilisant l'objet de communication soit averti des transitions d'état. Comme illustré dans la figure 2 ci-dessus, chaque événement est déclenché une fois après la transition de l’état de l’objet vers l’état nommé par l’événement. Les cinq événements sont du EventHandler type défini comme suit :
public delegate void EventHandler(object sender, EventArgs e);
Dans l'implémentation CommunicationObject, l'expéditeur est soit le CommunicationObject lui-même, soit l'objet passé en tant qu'expéditeur au constructeur CommunicationObject (si cette surcharge de constructeur a été utilisée). Le paramètre EventArgs, e est toujours EventArgs.Empty.
Rappels d'objets dérivés
Outre les cinq événements, CommunicationObject déclare huit méthodes virtuelles protégées conçues pour permettre à un objet dérivé d’être rappelé avant et après les transitions d’état.
Les méthodes CommunicationObject.Open et CommunicationObject.Close ont trois rappels associés à chacune d'elles. Par exemple, le CommunicationObject.Open correspond au CommunicationObject.OnOpening, au CommunicationObject.OnOpen et au CommunicationObject.OnOpened. Les méthodes associées à CommunicationObject.Close sont CommunicationObject.OnClose, CommunicationObject.OnClosing, et CommunicationObject.OnClosed.
De même, la méthode CommunicationObject.Abort a un CommunicationObject.OnAbort correspondant.
Alors que CommunicationObject.OnOpen, CommunicationObject.OnCloseet CommunicationObject.OnAbort n’ont pas d’implémentation par défaut, les autres rappels ont une implémentation par défaut qui est nécessaire pour la correction de l’ordinateur d’état. Si vous remplacez ces méthodes, veillez à appeler l’implémentation de base ou à la remplacer correctement.
CommunicationObject.OnOpening, CommunicationObject.OnClosing et CommunicationObject.OnFaulted déclenchent les événements correspondants CommunicationObject.Opening, CommunicationObject.Closing et CommunicationObject.Faulted. CommunicationObject.OnOpened et CommunicationObject.OnClosed définissez l’état de l’objet sur Ouvert et Fermé respectivement, puis déclenchez les événements correspondants CommunicationObject.Opened et CommunicationObject.Closed.
Méthodes de transition d’état
CommunicationObject fournit des implémentations d'Abort, Close et Open. Il fournit également une méthode Fault qui provoque une transition d'état vers l'état Faulted. La figure 2 montre l’ordinateur ICommunicationObject d’état avec chaque transition étiquetée par la méthode qui l’entraîne (les transitions sans étiquette se produisent à l’intérieur de l’implémentation de la méthode qui a provoqué la dernière transition étiquetée).
Remarque
Toutes les implémentations CommunicationObject d'obtentions/définitions d'état de communication sont synchronisées par thread.
Constructeur
CommunicationObject fournit trois constructeurs, dont tous conservent l’objet dans l’état Créé. Les constructeurs sont définis comme suit :
Le premier constructeur est un constructeur sans paramètre qui délègue à la surcharge du constructeur qui prend un objet :
protected CommunicationObject() : this(new object()) { … }
Le constructeur qui accepte un objet utilise ce paramètre comme objet à verrouiller lors de la synchronisation de l’accès à l’état de l’objet de communication :
protected CommunicationObject(object mutex) { … }
Enfin, un troisième constructeur accepte un paramètre supplémentaire utilisé comme argument expéditeur lorsque ICommunicationObject les événements sont déclenchés.
protected CommunicationObject(object mutex, object eventSender) { … }
Les deux constructeurs précédents définissent l’expéditeur sur ce paramètre.
Open, méthode
Condition préalable : l’état est créé.
Post-condition : l'état est Opened ou Faulted. Peut lever une exception.
La méthode Open() essaie d’ouvrir l’objet de communication et de définir l’état sur Ouvert. S’il rencontre une erreur, il définit l’état sur Faulted.
La méthode vérifie d’abord que l’état actuel est Créé. Si l'état actuel est Opening ou Opened, elle lève une InvalidOperationException. Si l'état actuel est Closing ou Closed, elle lève une CommunicationObjectAbortedException si l'objet a été arrêté et une ObjectDisposedException sinon. Si l'état actuel est Faulted, elle lève une CommunicationObjectFaultedException.
Il définit ensuite l’état sur Ouverture et appelle OnOpening() (qui déclenche l’événement Opening), OnOpen() et OnOpened() dans cet ordre. OnOpened() définit l’état sur Open et déclenche l’événement Open. Si l'un de ces appels lève une exception, Open() appelle Fault() et permet à l'exception de se propager. Le diagramme suivant montre le processus Open plus en détail.
Remplacez la méthode OnOpen pour implémenter une logique ouverte personnalisée, par exemple l’ouverture d’un objet de communication interne.
Close, méthode
Condition préalable : Aucune.
Post-condition : l'état est Closed. Peut lever une exception.
La méthode Close() peut être appelée à n’importe quel état. Il tente de fermer l’objet normalement. Si une erreur est rencontrée, elle met fin à l’objet. La méthode ne fait rien si l'état actuel est Closing ou Closed. Sinon, elle affecte la valeur Closing à l'état. Si l'état d'origine est Created, Opening ou Faulted, elle appelle Abort() (voir le diagramme suivant). Si l'état d'origine est Opened, elle appelle OnClosing() (laquelle déclenche l'événement Closing), OnClose() et OnClosed() dans cet ordre. Si l'un de ces appels lève une exception, Close() appelle Abort() et permet à l'exception de se propager. OnClosed() définit l’état sur Closed et déclenche l’événement Closed. Le diagramme suivant montre le processus de clôture plus en détail.
Remplacez la méthode OnClose pour implémenter une logique de fermeture personnalisée, telle que la fermeture d’un objet de communication interne. Toute logique de fermeture appropriée qui peut bloquer pendant une longue période (par exemple, en attendant que l’autre côté réponde) doit être implémentée dans OnClose(), car il prend un paramètre de délai d’expiration et parce qu’il n’est pas appelé dans le cadre d’Abort().
Abandon
Condition préalable : Aucune.
Post-condition : l'état est Closed. Peut lever une exception.
La méthode Abort() ne fait rien si l’état actuel est Fermé ou si l’objet a été arrêté avant (par exemple, en ayant peut-être Abort() s’exécutant sur un autre thread. Sinon, il définit l’état sur Closing et appelle OnClosing() (qui déclenche l’événement Closing), OnAbort() et OnClosed() dans cet ordre (n’appelle pas OnClose, car l’objet est arrêté, pas fermé). OnClosed() définit l’état sur Closed et déclenche l’événement Closed. En cas de levée d'une exception, celle-ci est à nouveau levée pour l'appelant d'Abort. Les implémentations d’OnClosing(), OnClosed() et OnAbort() ne doivent pas bloquer (par exemple, en entrée/sortie). Le diagramme suivant montre le processus d'interruption plus en détail.
Remplacez la méthode OnAbort pour implémenter une logique d’arrêt personnalisée, telle que la fin d’un objet de communication interne.
Erreur
La méthode Fault est spécifique à CommunicationObject et ne fait pas partie de l’interface ICommunicationObject. Il est inclus ici pour l’exhaustivité.
Condition préalable : Aucune.
Post-condition : l'état est Faulted. Peut lever une exception.
La méthode Fault() ne fait rien si l’état actuel est Faulted ou Closed. Sinon, il définit l’état sur Faulted et appelle OnFaulted(), ce qui déclenche l’événement Faulted. Si OnFaulted lève une exception, elle est à nouveau levée.
Méthodes ThrowIfXxx
CommunicationObject a trois méthodes protégées qui peuvent être utilisées pour lever des exceptions si l’objet est dans un état spécifique.
ThrowIfDisposed lève une exception si l'état est Closing, Closed ou Faulted.
ThrowIfDisposedOrImmutable lève une exception si l'état n'est pas Created.
ThrowIfDisposedOrNotOpen lève une exception si l'état n'est pas Opened.
Les exceptions levées dépendent de l'état. Le tableau suivant présente les différents états et le type d'exception correspondant levé en appelant une méthode ThrowIfXxx qui lève sur cet état.
| État | La méthode Abort a-t-elle été appelée ? | Cas d'exception |
|---|---|---|
| Date de création | N/A | System.InvalidOperationException |
| Ouverture | N/A | System.InvalidOperationException |
| Ouvert | N/A | System.InvalidOperationException |
| Fermeture | Oui | System.ServiceModel.CommunicationObjectAbortedException |
| Fermeture | Non | System.ObjectDisposedException |
| Fermé | Oui | System.ServiceModel.CommunicationObjectAbortedException lorsque un objet a été fermé par un appel précédent et explicite de la commande "Abort". Si vous appelez Close sur l'objet, alors une System.ObjectDisposedException est levée. |
| Fermé | Non | System.ObjectDisposedException |
| Erreur | N/A | System.ServiceModel.CommunicationObjectFaultedException |
Délais d’expiration
Plusieurs des méthodes que nous avons abordées ont abordé les paramètres de délai d’attente. Il s’agit de Close, Open (certaines surcharges et versions asynchrones), OnClose et OnOpen. Ces méthodes sont conçues pour permettre de longues opérations (par exemple, le blocage sur l’entrée/sortie lors de la fermeture normale d’une connexion) afin que le paramètre de délai d’expiration indique la durée pendant laquelle ces opérations peuvent prendre avant d’être interrompues. Les implémentations de l’une de ces méthodes doivent utiliser la valeur de délai d’attente fournie pour s’assurer qu’elle revient à l’appelant dans ce délai d’expiration. Les implémentations d’autres méthodes qui ne prennent pas de délai d’attente ne sont pas conçues pour les opérations longues et ne doivent pas bloquer l’entrée/sortie.
Les exceptions sont les surcharges Open() et Close() qui ne prennent pas de délai d'expiration. Celles-ci utilisent une valeur de délai d’expiration par défaut fournie par la classe dérivée. CommunicationObject expose deux propriétés abstraites protégées nommées DefaultCloseTimeout et DefaultOpenTimeout définies comme suit :
protected abstract TimeSpan DefaultCloseTimeout { get; }
protected abstract TimeSpan DefaultOpenTimeout { get; }
Une classe dérivée implémente ces propriétés pour fournir le délai d’expiration par défaut pour les surcharges Open() et Close() qui ne prennent pas de valeur de délai d’expiration. Ensuite, les implémentations Open() et Close() délèguent à la surcharge qui prend un délai d'attente en la transmettant à la valeur de délai d'attente par défaut, par exemple :
public void Open()
{
this.Open(this.DefaultOpenTimeout);
}
IDefaultCommunicationTimeouts
Cette interface comporte quatre propriétés en lecture seule pour fournir des valeurs de délai d’attente par défaut pour l’ouverture, l’envoi, la réception et la fermeture. Chaque implémentation est chargée d’obtenir les valeurs par défaut de la manière appropriée. En guise de commodité, ChannelFactoryBase et ChannelListenerBase définissent par défaut ces valeurs à 1 minute chacune.