2010-10-01 16 views
1

J'ai un service qui répond aux messages sur un MSMQ, en utilisant WCF. Lorsque le message est bien formaté, cela fonctionne normalement, et nous sommes heureux. Lorsque le message est destiné à un service différent et que l'action est différente, le message reste dans la file d'attente, nous recevons des entrées de journal, nous réparons et nous sommes satisfaits. Mais lorsque le message a la bonne action, mais contient des éléments XML qui ne peuvent pas être désérialisés par le serveur, le message disparaît de la file d'attente, nous n'obtenons pas d'entrées de journal et nous n'avons aucune idée de ce qui s'est passé. nous ne sommes pas heureux.MSMQ par WCF avale des messages mal formatés, pas d'erreurs, pas d'avertissements

J'ai essayé d'ajouter un IErrorHandler. J'ai essayé d'ajouter un gestionnaire d'événement Faulted. La seule chose que je peux faire est d'utiliser la journalisation des diagnostics intégrée dans WCF. Est-il possible que je puisse répondre à une erreur comme celle-ci dans le code, avec mon propre gestionnaire de journal ou d'erreur?

Mes files d'attente sont transactionnelles, mais cela ne semble pas être différent de ce problème. Cela se produit sur la version MSMQ 3.0, sur Windows Server 2003.

Ce code source présente le problème:

class Program : IErrorHandler { 
    private static Uri QueueUri = new Uri("net.msmq://localhost/private/server_queue"); 

    static void Main(string[] args) { 
     Program program = new Program(); 

     if (args.Length > 0) { 
      if (args[0] == "server") { 
       program.Server(); 
      } else if (args[0] == "bad") { 
       program.BadClient(); 
      } 
     } else { 
      program.Client(); 
     } 
    } 

    public void BadClient() { 
     using (var client = new BadServiceClient(QueueUri)) { 
      client.Do(new [] {new BadStuff { BadMessage = "hi" }}); 
     } 
    } 

    public void Client() { 
     using (var client = new ServiceClient(QueueUri)) { 
      client.Do(new [] {new Stuff {Message = "hi"}}); 
     } 
    } 

    public void Server() { 
     var serviceHost = new ServiceHost(typeof(Service)); 
     serviceHost.AddServiceEndpoint(typeof (IService), new NetMsmqBinding(), QueueUri); 
     serviceHost.Open(); 

     serviceHost.Faulted += serviceHost_Faulted; 
     serviceHost.UnknownMessageReceived += new EventHandler<UnknownMessageReceivedEventArgs>(serviceHost_UnknownMessageReceived); 
     foreach (ChannelDispatcher dispatcher in serviceHost.ChannelDispatchers) { 
      dispatcher.ErrorHandlers.Add(this); 
     } 

     Console.WriteLine("press the any key"); 
     Console.ReadKey(true); 
    } 

    void serviceHost_UnknownMessageReceived(object sender, UnknownMessageReceivedEventArgs e) { 
     Console.WriteLine("unknown message: {0}", e); 
    } 

    private static void serviceHost_Faulted(object sender, EventArgs e) { 
     Console.WriteLine("fault: {0}", e); 
    } 

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault) { 
     Console.WriteLine("handling error: {0}", error); 
    } 

    public bool HandleError(Exception error) { 
     Console.WriteLine("handling error: {0}", error); 
     return true; 
    } 
} 

[ServiceContract] 
public interface IService { 
    [OperationContract(IsOneWay = true, Action = "do")] 
    void Do(IEnumerable<Stuff> stuffs); 
} 

[ServiceContract] 
public interface IBadService { 
    [OperationContract(IsOneWay = true, Action = "do")] 
    void Do(IEnumerable<BadStuff> stuffs); 
} 

class ServiceClient : ClientBase<IService>, IService { 
    public ServiceClient(Uri uri) : base(new NetMsmqBinding(), new EndpointAddress(uri)) {} 

    public void Do(IEnumerable<Stuff> stuffs) { 
     Channel.Do(stuffs); 
    } 
} 

class BadServiceClient : ClientBase<IBadService>, IBadService { 
    public BadServiceClient(Uri uri) : base(new NetMsmqBinding(), new EndpointAddress(uri)) {} 

    public void Do(IEnumerable<BadStuff> stuffs) { 
     Channel.Do(stuffs); 
    } 
} 

[ServiceBehavior(TransactionTimeout = "00:5:00", InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)] 
class Service : IService { 
    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)] 
    public void Do(IEnumerable<Stuff> stuffs) { 
     foreach (var stuff in stuffs) { 
      Console.WriteLine("service doing stuff, message: " + stuff.Message); 
     } 
    } 
} 

[DataContract] 
public class Stuff { 
    [DataMember] 
    public string Message; 
} 

[DataContract] 
public class BadStuff : Stuff { 
    [DataMember] 
    public string BadMessage; 
} 
+0

Il y a peu de files d'attente système pour chaque file d'attente d'application qui peut être activée. L'un d'eux sont DeadLetterQueue et PoisonQueue. Ces files d'attente contiennent des messages ayant échoué. –

+0

Malheureusement, aucun message ne doit être trouvé dans la file d'attente des lettres mortes ou dans la file d'attente des messages empoisonnés. J'utilise MSMQ 3.0 sur Windows Server 2003. –

Répondre

0

Ceci est très en retard, mais en y ajoutant une réponse pour les autres qui peuvent avoir un problème similaire comme moi. Notez que l'utilisation de MSMQ n'est pas liée au fait de ne pas pouvoir extraire le message malformé. Comme Tim l'a mentionné lors de l'utilisation d'une implémentation IDispatchMessageInspector, le message ne s'affichera pas s'il ne parvient pas à désérialiser le code XML car il est mal formé (par exemple, il contient un caractère &).

La seule chose que je pouvais trouver est d'activer un message régulier WCF le traçage du logMalformedMessages est définie sur true sous l'élément messageLogging selon cette documentation (espérons-MS ne se déplacent pas le lien):

Configuring Message Logging