2008-12-06 5 views
4

J'ai une application cliente qui signale une fois de sa progression un service. L'appel de méthode au service est marqué avec IsOneWay = true, car la notification n'a besoin d'aucune valeur de retour et je ne souhaite pas différer.Que se passe-t-il dans WCF à des méthodes avec IsOneWay = true à la fin de l'application

Le client peut signaler des erreurs au service, et par la suite il se termine.

La question est: est-ce qu'un appel de méthode oneway renvoie au code appelant après avoir envoyé le message? ou il met en file d'attente le message et plus tard il est envoyé par un autre thread?

Les deux processus (le client et le service) sont sur la même machine et j'ai remarqué que parfois (lorsque la machine est surchargée) le service n'obtient pas la notification d'erreur. Je soupçonne que la deuxième option que j'ai mentionnée arrive, mais je ne suis pas sûre.

Si j'ai raison, comment puis-je m'assurer que la notification est envoyée et conserver la méthode dans un sens?

Répondre

1

Vous ne pouvez pas "vous assurer que la notification est envoyée" ... et "conserver la méthode dans un sens". Cela va un peu à l'encontre de ce que "OneWay" veut dire :)

Si vous voulez vous assurer que le message est envoyé, c'est possible de faire TwoWay. Vous ne remarquerez probablement pas la légère baisse de performance. Et si le serveur et le client sont sur la même machine que celle que vous avez mentionnée ... alors vous ne remarquerez pas du tout les performances.

+0

Je sais que je ne peux pas m'assurer que la méthode sera appelée au service (reçu) et c'est ok. Parce que c'est sur la même machine, je crois que c'est assez fiable pour être toujours reçu. Cependant, comment puis-je m'assurer que le client envoie le message d'appel de la méthode? et aussi garder la méthode à sens unique? –

2

Vérifiez ce post pour quelques informations détaillées: http://kennyw.com/?p=130

, je crois également que si vous avez une messagerie fiable a permis que la demande serait vérifiée comme envoyé avec succès, mais comme les notes de poste ci-dessus, le service terminez la connexion après ce point.

0

Je suis d'accord avec Timothy. Je tiens également à ajouter que le service WCF conserve une file d'attente pour les messages entrants. Cette file d'attente peut devenir pleine si le service n'est pas en mesure de traiter les messages aussi rapidement qu'ils arrivent. Lorsque la file d'attente entrante est pleine, WCF supprimera les nouveaux messages.

Je ne sais pas ce qui se passe du côté client si des messages unidirectionnels sont supprimés. Je suppose qu'aucune exception/faute n'est levée mais je ne le sais pas à coup sûr.

1

Cela peut être un bon endroit pour utiliser un netMsmqBinding. Tous les messages MSMQ sont intrinsèquement OneWay parce que les files d'attente sont intrinsèquement déconnectées. Une fois que le client met en file d'attente le message avec un client netMsmq, il peut s'arrêter en toute sécurité et le serveur peut ensuite récupérer le message et le traiter.

8

Bonne question. Avant que l'application cliente n'appelle une méthode, elle ouvre le canal. Le canal est utilisé pour toutes les communications de données. Il y a deux manières d'envoyer: 1) session fiable - quand vos paquets sont désendettés de manière fiable et les paquets fissurés sont renvoyés, 2) commande - quand les demandes sur le service sont calculées dans l'ordre où ils ont été transférés du client (pas comment ils sont livrés) . Si vous avez une session ordonnée fiable et que l'hôte de service rencontre des problèmes avec vos données après la fermeture de l'application, l'hôte essaiera de demander au client de renvoyer les données et après aucune réponse, rejettera tout ce que vous demanderez. Dans une autre situation (non fiable) après l'ouverture du canal, vous pouvez envoyer des données et détruire la communication, la méthode oneway calculera votre demande, s'il n'y aura pas d'exception.

Pour tester certaines possibilités avec le problème de service (pas exactement votre client paroblem est cependant utile) créer une solution:

1) projet de bibliothèque "WcfContracts" avec un fichier "IService1.cs":

[ServiceContract] 
    public interface IService1 
    { 
     [OperationContract] 
     void ThrowException(); 

     [OperationContract(IsOneWay=true)] 
     void ThrowExceptionUseIsOneWay(); 
    } 

2) projet Console "WcfConsoleHoster" qui a deux "référence WcfContracts", et se compose des trois fichiers:

a) Service1.cs, qui est mise en œuvre de services

public class Service1 : WcfContracts.IService1 
{  
     public void ThrowException() 
     { 
      throw new Exception("Basic exception"); 
     } 

     public void ThrowExceptionUseIsOneWay() 
     { 
      throw new Exception("Basic exception using IsOneWay=true"); 
     } 
} 

b) Program.cs, qui a un point d'entrée par défaut et commence juste le service

static void Main(string[] args) 
    { 
     ServiceHost host = new ServiceHost(typeof(Service1)); 
     host.Open(); 
     Console.WriteLine("host 1 opened"); 
     Console.ReadKey(); 
    } 

c) service "App.config"

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.serviceModel> 
    <services> 
     <service behaviorConfiguration="behavourHttpGet" name="WcfConsoleHoster.Service1"> 
     <host> 
      <baseAddresses> 
      <add baseAddress="http://localhost:8732/Design_Time_Addresses/WcfConsoleHoster/Service1/" /> 
      </baseAddresses> 
     </host> 
     <endpoint binding="wsHttpBinding" contract="WcfContracts.IService1" />   
     <endpoint address ="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name="behavourHttpGet"> 
      <serviceMetadata httpGetEnabled="true" /> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    </system.serviceModel> 
</configuration> 

3) projet Console "WcfConsoleClient" , qui appelle simplement le service

a) Dans "Program.cs"

Console.WriteLine("Wcf client. Press any key to start"); 
Console.ReadKey(); 
ChannelFactory<IService1> factory = new ChannelFactory<IService1>("Service1_Endpoint"); 
IService1 channel = factory.CreateChannel(); 
//Call service method 
channel.ThrowException(); 

Console.WriteLine("Operation executed"); 
Console.ReadKey(); 

b) Client "App.config"

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.serviceModel> 
    <client> 
     <endpoint name="Service1_Endpoint" 
     address="http://localhost:8732/Design_Time_Addresses/WcfConsoleHoster/Service1/" 
     binding="wsHttpBinding" 
     contract="WcfContracts.IService1"> 
     </endpoint> 
    </client> 
    </system.serviceModel> 
</configuration> 

1. Exception Throwing. D'abord, nous appelons la méthode bidirectionnelle qui déclenche une exception dans l'hôte du serveur. Puis cette exception revient au client et le canal l'élève du côté client, l'application est détruite. Bien sûr, vous pouvez gérer cela avec try() catch {} block.

Regardons la même chose avec méthode unidirectionnelle en appelant channel.ThrowExceptionUseIsOneWay();. L'exception est déclenchée dans l'hôte de service, mais il n'y a pas d'exception côté client et l'opération est exécutée. Il est important de réaliser que le canal sera indisponible pour la prochaine utilisation.

Donc, IsOneWay=true fonctionne comme prévu - il envoie un message seulement d'une manière. Vous ne pouvez pas retourner un objet de la méthode (void est attendu) et vous ne pouvez pas utiliser FaultContract ou obtenir InvalidOperationException après le démarrage du service.

2. Thread.Sleep(). Le test suivant est en opération massive avec Thread.Sleep(). IService1 est étendu à

[OperationContract] 
    int ThreadSleep(); 

    [OperationContract(IsOneWay=true)] 

et la réalisation en Service1.cs est en attente pendant 5 secondes

public int ThreadSleep() 
{ 
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); 
    return 1; 
} 

public void ThreadSleepUseIsOneWay() 
{ 
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); 
} 

maintenant une modification de bit pour le client pour le comptage écoulé le temps d'appel

System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); 
stopwatch.Start(); 
//call methode 
channel.ThreadSleep(); 
stopwatch.Stop(); 
Console.WriteLine(string.Format("Operation executed in {0} seconds", stopwatch.Elapsed.Seconds)); 
Console.ReadKey(); 

Appel deux méthode de façonThreadSleep() a le résultat « opération exécutée en 7 secondes "(5 secondes pour le sommeil du thread + 2 secondes pour l'initialisation du canal).

One way method avec l'appel channel.ThreadSleepUseIsOneWay() a comme résultat "0 secondes"! Il n'y a pas d'attente pour la réponse du service!

Il est préférable d'utiliser NetNamedPipeBinding, qui est une connexion fiable et rapide sur la même machine.

1

J'ai eu un problème similaire (appel unilatéral ne faisant rien ou jetant une exception). J'ai trouvé que le désérialiseur responsable de la transformation de l'argument de méthode de xml en objets créait une exception. Ma méthode de service n'a jamais été atteinte et aucune exception n'a été renvoyée car il s'agissait d'un appel à sens unique. Je ne l'ai pas détecté avant d'avoir temporairement désactivé le 'one-way', mon exception a donc été renvoyée au client.

Espérons que cela aide quelqu'un d'autre dans une situation similaire.

+0

Cela m'a aidé à résoudre mon problème .. –

Questions connexes