Accès distant asynchrone
La programmation asynchrone dans un scénario d'accès distant est identique à la programmation asynchrone dans un domaine d'application ou un contexte unique, à l'exception de la configuration et des exigences spécifiques à .NET Remoting. Pour obtenir un exemple complet qui utilise .NET Remoting et les délégués synchrones et asynchrones, consultez Exemple d'accès distant : accès distant asynchrone.
Tout comme pour la programmation asynchrone de domaine d'application unique, l'utilisation de la programmation asynchrone dans un scénario .NET Remoting implique les points suivants :
- L'appelant décide si un appel distant particulier est asynchrone.
- Les types distants ne sont pas tenus de prendre explicitement en charge le comportement asynchrone de leurs clients.
- Le runtime applique une sécurité complète des types.
- Vous devez utiliser de manière appropriée les objets System.Threading pour faire attendre ou synchroniser vos méthodes.
Cependant, dans une application qui appelle au-delà des limites de contexte ou de domaine d'application, .NET Remoting nécessite que vous configuriez le système .NET Remoting et que vous vous assuriez que votre modèle de programmation client se qualifie également comme cible pour un appel distant. La raison est assez simple : si vous utilisez des appels asynchrones, vous pouvez utiliser une fonction de rappel que le système .NET Remoting appellera à partir du serveur. Par exemple, si vous passez un délégué à une méthode static (qui ne peut pas être distante) ou oubliez de définir un port pour votre canal sur « 0 » (pour permettre au système de sélectionner un port client en votre nom), votre appel au serveur peut aboutir, mais vous n'aurez aucun moyen d'obtenir le résultat car le rappel vers le client n'aboutira pas.
Votre client n'a pas besoin d'étendre MarshalByRefObject ni de configurer un type distant lui-même, mais en dehors de cela il doit suivre les mêmes règles que n'importe quel type distant destiné à être un serveur :
- Une instance doit recevoir la fonction de rappel.
- Un canal doit être inscrit pour écouter la fonction de rappel.
Paradigme de programmation asynchrone
Le processus de programmation asynchrone est aussi simple que celui d'un domaine d'application unique :
- Créez une instance d'un objet qui peut recevoir un appel distant à une méthode.
- Enveloppez cette méthode d'instance à l'aide d'un objet AsyncDelegate.
- Enveloppez la méthode distante à l'aide d'un autre délégué.
- Appelez la méthode BeginInvoke sur le deuxième délégué, en passant des arguments, AsyncDelegate et des objets pour maintenir l'état (ou une référence null, Nothing dans Visual Basic).
- Attendez que l'objet serveur appelle votre méthode de rappel.
Bien qu'il s'agisse de l'approche générale, celle-ci peut varier dans une certaine mesure. Si, à tout moment, vous souhaitez attendre qu'un appel particulier soit retourné, vous prenez simplement l'interface IAsyncResult retournée à partir de l'appel BeginInvoke, extrayez l'instance WaitHandle pour cet objet et appelez la méthode WaitOne comme le montre l'exemple de code suivant.
Dim RemoteCallback As New AsyncCallback(AddressOf Me.OurCallBack)
Dim RemoteDel As New RemoteAsyncDelegate(AddressOf obj.RemoteMethod)
Dim RemAr As IAsyncResult = RemoteDel.BeginInvoke(RemoteCallback, Nothing)
RemAr.AsyncWaitHandle.WaitOne()
[C#]
AsyncCallback RemoteCallback = new AsyncCallback(this.OurCallBack);
RemoteAsyncDelegate RemoteDel = new RemoteAsyncDelegate(obj.RemoteMethod);
IAsyncResult RemAr = RemoteDel.BeginInvoke(RemoteCallback, null);
RemAr.AsyncWaitHandle.WaitOne();
Vous pouvez également attendre, soit dans une boucle qui vérifie si l'appel a abouti, soit en utilisant les primitives System.Threading telles que la classe ManualResetEvent, puis finir l'appel vous-même.
Dim RemoteCallback As New AsyncCallback(AddressOf Me.OurCallBack)
Dim RemoteDel As New RemoteAsyncDelegate(AddressOf obj.RemoteMethod)
Dim RemAr As IAsyncResult = RemoteDel.BeginInvoke(RemoteCallback, Nothing)
If RemAr.IsCompleted Then
Dim del As RemoteAsyncDelegate = CType(CType(RemAr, AsyncResult).AsyncDelegate, RemoteAsyncDelegate)
Console.WriteLine(("**SUCCESS**: Result of the remote AsyncCallBack: " _
+ del.EndInvoke(RemAr)))
' Allow the callback thread to interrupt the primary thread to execute the callback.
Thread.Sleep(1)
End If ' Do something.
[C#]
AsyncCallback RemoteCallback = new AsyncCallback(this.OurCallBack);
RemoteAsyncDelegate RemoteDel = new RemoteAsyncDelegate(obj.RemoteMethod);
IAsyncResult RemAr = RemoteDel.BeginInvoke(RemoteCallback, null);
if (RemAr.IsCompleted){
RemoteAsyncDelegate del = (RemoteAsyncDelegate)((AsyncResult) RemAr).AsyncDelegate;
Console.WriteLine("**SUCCESS**: Result of the remote AsyncCallBack: "
+ del.EndInvoke(RemAr) );
// Allow the callback thread to interrupt the primary thread to execute the callback.
Thread.Sleep(1);
}
Enfin, votre thread principal peut créer ManualResetEvent et attendre la fonction de rappel qui signale ensuite ManualResetEvent comme étant la dernière ligne avant le retour. Pour obtenir un exemple de ce type d'attente, consultez les commentaires de code source dans Exemple d'accès distant : accès distant asynchrone.
Problèmes
Remarquez que si le client est une classe liée au contexte qui nécessite un contexte synchronisé, la fonction de rappel est distribuée via l'infrastructure de contexte .NET Remoting. Cela signifie que la fonction de rappel elle-même peut s'exécuter de manière asynchrone par rapport à ses appelants pour ces contextes-là. C'est également le comportement de l'attribut OneWayAttribute lors de la décoration de signatures de méthode de rappel. N'importe laquelle de ces méthodes de rappel peut s'exécuter de manière synchrone ou asynchrone en fonction de l'appelant distant, et l'appelant n'est pas en mesure de savoir si un tel appel a abouti lors du retour du contrôle de l'exécution.
De plus, l'appel de la méthode EndInvoke avant que l'opération asynchrone soit achevée une deuxième fois à l'aide du même IAsyncResult est indéfini.
Voir aussi
Vue d'ensemble de .NET Remoting | Exemple d'accès distant : accès distant asynchrone | Configuration