2008-11-24 4 views
30

J'ai un service WCF qui ne doit pas entrer dans l'état défectueux. S'il existe une exception, elle doit être enregistrée et le service doit continuer sans interruption. Le service a un contrat d'opération à sens unique et lit les messages d'un MSMQ.Comment empêcher un service WCF d'entrer dans un état défectueux?

Mes problèmes sont de deux ordres:

  1. Le service semble avaler une exception/faute si je suis incapable de déboguer. Comment est-ce que j'obtiens le service pour exposer l'exception de sorte que je puisse le loger ou le manipuler?
  2. Le service est entrant dans un état en défaut après cette exception est avalée. Comment j'empêche le service d'entrer dans un état défectueux?
+0

ici vous pouvez obtenir toute la théorie http://msdn.microsoft.com/en-us/library/ms789041(v=vs.110).aspx –

Répondre

18

La plupart, si toutes les exceptions ne peuvent pas être vues dans le suivi WCF (Configuring Tracing) et la trace est mieux vue avec le Service Trace Viewer.

De toute évidence, ce n'est pas quelque chose que vous devriez avoir en cours d'exécution toute la journée dans un environnement de production, mais cela aide quand même le dépannage. En dehors de cela, notez que oneways ne peut pas fonctionner comme un vrai "fire and forget" selon le mode de session que vous utilisez. Si vous avez configuré votre service pour SessionMode.Allowed ou même SessionMode.Required, l'opération oneway s'exécutera comme si elle n'était pas du tout un chemin (cela peut être observé lors de l'utilisation de oneways sur netTcpBinding). Pour être franc, cependant, je ne sais pas si cela change le type d'exceptions que vous pouvez obtenir, ou quand vous les obtenez. Cependant, dans tous les cas, vous devriez obtenir une exception si la requête n'a pas pu être envoyée du tout. AFAIK, le oneway "se termine" quand il est interrogé avec succès sur le côté serveur. Il y a donc une place pour les exceptions (liées au cadre de la WCF) jusque-là (la sérialisation/désérialisation vient à l'esprit). Ensuite, ces exceptions liées au framework sont mieux vues (même un IErrorHandler ne les obtient pas toutes en raison du fait qu'il est appelé dans le flux requête/réponse) en utilisant le trace/traceviewer mentionné ci-dessus.

+0

Je suis confronté au même problème. J'ai le service s'exécutant sur Production avec netTcpBinding ayant peu de méthodes comme IsOneway = True et SessionMode set Cependant, quand il y a une exception, les services passent à l'état Faulted. Pour le faire fonctionner, je dois le redémarrer –

11

Des exceptions peuvent endommager le proxy. Vous ne pouvez pas AFAIK faire beaucoup à ce sujet: ne provoque pas d'exceptions ;-p

Je suis un peu surpris que l'one-way pose toujours un problème, mais pour avaler dans le genre l, il y a 3 aspects:

  1. lancez-vous faults? ou des exceptions? il importe (et devrait être "défauts")
  2. comme un hack, vous pouvez activer les messages d'exception de débogage - mais éteignez s'il vous plaît !!!
  3. "utilisez-vous" l'objet de service? J'ai juste blogged sur ce sujet précis ... fondamentalement, votre "using" peut avaler l'exception. 3 options:

    • ne pas utiliser "en utilisant"
    • sous-classe le proxy et substituez Dispose()
    • l'envelopper, selon le blog
+0

Merci pour les commentaires Marc. J'ai arrêté d'utiliser en utilisant pour essayer de traquer les exceptions mais pas de chance. La couche de gestion à laquelle le service WCF appelle lance des exceptions mais celles-ci sont avalées quelque part ... Mystère ... – Guy

+1

Vous pouvez essayer de passer à FaultException où T est une erreur publiée - cela peut aider les choses.Et notez qu'il est toujours très important de fermer le proxy; simplement que "utiliser" ne fait pas nécessairement ce que nous voulons à cette occasion. –

+0

Je pense que seules les exceptions qui n'ont pas été capturées et emballées par le service seront défectueuses, mais pas toutes les exceptions –

7

Environ 2) ...

L'astuce est que vous devez utiliser « à l'aide » et doit toujours appeler Abort() sur le proxy qui a lancé une exception. L'article WCF Gotcha explique tout cela.

Nous utilisons une classe de service inspirée de cet article qui enveloppe les appels de service. Ceci est un exemple de code de mon projet:

ServiceHelper<CodeListServiceClient, CodeListService.CodeListService>.Use(
    proxy => seasonCodeBindingSource.DataSource = proxy.GetSeasonCodes(brandID); 
); 

Et c'est le code de ServiceHelper, légèrement modifié à partir de l'article. Jusqu'à présent, cela nous a vraiment bien servi.

using System; 
using System.ServiceModel; 

namespace Sportina.EnterpriseSystem.Client.Framework.Helpers 
{ 
    public delegate void UseServiceDelegate<TServiceProxy>(TServiceProxy proxy); 

    public static class ServiceHelper<TServiceClient, TServiceInterface> where TServiceClient : ClientBase<TServiceInterface>, new() where TServiceInterface : class 
    { 
     public static void Use(UseServiceDelegate<TServiceClient> codeBlock) 
     { 
      TServiceClient proxy = null; 
      bool success = false; 
      try 
      { 
       proxy = new TServiceClient();    
       codeBlock(proxy); 
       proxy.Close(); 
       success = true; 
      } 
      catch (Exception ex) 
      { 
       Common.Logger.Log.Fatal("Service error: " + ex);         
       throw; 
      } 
      finally 
      { 
       if (!success && proxy != null) 
        proxy.Abort(); 
      } 
     } 
    } 
} 
+3

Le lien vers le message 'WCF Gotcha' est cassé, mais je n'ai pas assez de rep pour l'éditer. Voici le bon lien: http://old.iserviceoriented.com/blog/post/Indisposable+-+WCF+Gotcha+1.aspx. – yzorg

+0

@yzorg - Merci pour le lien, je viens de mettre à jour la réponse. – LamonteCristo

6

J'ai eu un problème où le canal est resté dans un état défectueux après une exception ReceiveTimeout. Cela rendrait le service rendu inutilisable par les connexions suivantes.

Le correctif pour récupérer le service de l'état de défaut pour moi était de gérer l'événement Faulted du canal de communication:

channelFactory = new ChannelFactory<IService>(endpoint); 
channelFactory.Faulted += OnChannelFaulted; 
var channel = channelFactory.CreateChannel(); 

Définissez ensuite OnChannelFaulted:

void OnChannelFaulted(object sender, EventArgs e) 
{ 
    channelFactory.Abort(); 
} 

Note: Je suis en cours d'exécution la configuration de WCF via le code par rapport à l'aide de liaisons dans le Web.config.

8

Habituellement, le service WCF est hébergé dans un ServiceHost, si le service WCF échoue, la seule option est de supprimer le service WCF et d'en démarrer un nouveau.

Le ServiceHost a un événement déclencheur « FAULTED » qui est activé lorsque le service WCF échoue:

ServiceHost host = new ServiceHost(new Service.MyService()); 
host.Faulted += new EventHandler(host_faulted); 
host.Open(); 

Il est possible d'obtenir l'exception causant la faute, mais il faut un peu plus de travail:

public class ErrorHandler : IErrorHandler 
{ 
    public void ProvideFault(Exception error, MessageVersion version, ref Message fault) 
    { 

    } 

    public bool HandleError(Exception error) 
    { 
     Console.WriteLine("exception"); 
     return false; 
    } 
} 

public class ErrorServiceBehavior : IServiceBehavior 
{ 
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
    { 

    } 

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) 
    { 

    } 

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
    { 
     ErrorHandler handler = new ErrorHandler(); 
     foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers) 
     { 
      dispatcher.ErrorHandlers.Add(handler); 
     } 
    } 
} 

ServiceHost host = new ServiceHost(new Service.MyService()); 
host.Faulted += new EventHandler(host_faulted); 
host.Description.Behaviors.Add(new ErrorServiceBehavior()); 
host.Open(); 

Crédits http://www.haveyougotwoods.ca/2009/06/24/creating-a-global-error-handler-in-wcf

+1

J'ai essayé ceci mais la méthode HandleError n'est jamais atteinte, même si j'appuie sur le gestionnaire d'événement Faulted. – Brent

Questions connexes