2010-01-05 7 views
8

J'ai une application intranet personnalisée qui n'a aucune exigence d'interopérabilité. Nous construisons par programmation un canal NetTcp en mode duplex pour passer des messages. Nous voulions changer l'encodage des messages, mais nous n'avons pas réussi à comprendre comment y arriver.Comment modifier par programme le codage de message WCF pour NetTcp?

L'approche que nous avons pris (sans succès) a été d'étendre la NetTcpBinding dans une nouvelle classe appelée LeanTcpBinding comme suit:


internal class LeanTcpBinding : NetTcpBinding 
{ 
    private static readonly ILog _log = 
     LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 

    public override BindingElementCollection CreateBindingElements() 
    { 
     BindingElementCollection bindingElementCollection = base.CreateBindingElements(); 
     BindingElement encodingElement = bindingElementCollection.FirstOrDefault(
      bindingElement => bindingElement is BinaryMessageEncodingBindingElement); 
     if (encodingElement != null) 
     { 
      int index = bindingElementCollection.IndexOf(encodingElement); 
      bindingElementCollection.RemoveAt(index); 
      bindingElementCollection.Insert(index, new LeanBinaryMessageEncodingBindingElement()); 
     } 
     else 
     { 
      _log.Warn("Encoding not found"); 
     } 

     return bindingElementCollection; 
    } 
} 

, nous sommes évidemment essayer de remplacer le BinaryMessageEncodingBindingElement par défaut avec notre propre. Juste pour avoir l'utilisation a commencé, le LeanBinaryMessageEncodingBindingElement est une extension du BinaryMessageEncodingBindingElement comme suit:


internal class LeanBinaryMessageEncodingBindingElement : MessageEncodingBindingElement 
{ 
     private readonly BinaryMessageEncodingBindingElement _bindingElement; 

     /// 
     /// Initializes a new instance of the class. 
     /// 
     public LeanBinaryMessageEncodingBindingElement() 
     { 
      _bindingElement = new BinaryMessageEncodingBindingElement(); 
     } 

     /// 
     /// Initializes a new instance of the class. 
     /// 
     /// The binding element. 
     public LeanBinaryMessageEncodingBindingElement(BinaryMessageEncodingBindingElement bindingElement) 
     { 
      _bindingElement = bindingElement; 
     } 

     /// 
     /// Initializes a new instance of the class. 
     /// 
     /// The element to be cloned. 
     /// The binding element. 
     public LeanBinaryMessageEncodingBindingElement(MessageEncodingBindingElement elementToBeCloned, BinaryMessageEncodingBindingElement bindingElement) 
      : base(elementToBeCloned) 
     { 
      _bindingElement = bindingElement; 
     } 

     /// 
     /// When overridden in a derived class, returns a copy of the binding element object. 
     /// 
     /// 
     /// A object that is a deep clone of the original. 
     /// 
     public override BindingElement Clone() 
     { 
      return new LeanBinaryMessageEncodingBindingElement(
       (BinaryMessageEncodingBindingElement)_bindingElement.Clone()); 
     } 

     /// 
     /// When overridden in a derived class, creates a factory for producing message encoders. 
     /// 
     /// 
     /// The used to produce message encoders. 
     /// 
     public override MessageEncoderFactory CreateMessageEncoderFactory() 
     { 
      return new LeanBinaryMessageEncoderFactory(_bindingElement.CreateMessageEncoderFactory()); 
     } 

     /// 
     /// When overridden in a derived class, gets or sets the message version that can be handled by the message encoders produced by the message encoder factory. 
     /// 
     /// 
     /// The used by the encoders produced by the message encoder factory. 
     /// 
     public override MessageVersion MessageVersion 
     { 
      get { return _bindingElement.MessageVersion; } 
      set { _bindingElement.MessageVersion = value; } 
     } 
} 

Lorsque je tente d'utiliser la liaison qu'il fait exactement ce que je pense qu'il devrait le faire ... il remplace le BinaryMessageEncodingBindingElement. Cependant, je ne reçois jamais d'appels à LeanBinaryMessageEncodingBindingElement.CreateMessageEncoderFactory(), même si les messages sont échangés sur le canal.

Quelqu'un at-il des suggestions sur la façon de le faire correctement?

+0

Qu'avez-vous essayé de faire? La permanence? Est-ce que cela s'est amélioré? –

Répondre

7

Kenny loup a précisé ce qui manquait et il est documenté dans l'entrée de blog ci-dessous.

http://kennyw.com/?p=170

Pour les impatients, le problème est que par défaut, le MessageEncoderBindingElement ne s'ajoute pas aux paramètres de liaison du contexte. Par conséquent, lorsque le transport va plus tard trouver le MessageEncoderBindingElement il ne peut pas trouver celui que vous (ou vous) avez créé et a l'échec silencieux que j'ai noté dans mon message d'origine.

Malheureusement, vous devrez remplacer toutes les méthodes CanBuildXXX et BuildXXX comme suit pour vous assurer que vous ajoutez l'élément de liaison aux paramètres de liaison du contexte.

 

     public override bool CanBuildChannelFactory(BindingContext context) 
     { 
      if (context == null) { 
       throw new ArgumentNullException("context"); 
      } 

      context.BindingParameters.Add(this); 
      return context.CanBuildInnerChannelFactory(); 
     } 

     public override bool CanBuildChannelListener(BindingContext context) 
     { 
      if (context == null) { 
       throw new ArgumentNullException("context"); 
      } 

      context.BindingParameters.Add(this); 
      return context.CanBuildInnerChannelListener(); 
     } 

     public override IChannelFactory BuildChannelFactory(BindingContext context) 
     { 
      if (context == null) { 
       throw new ArgumentNullException("context"); 
      } 

      context.BindingParameters.Add(this); 
      return context.BuildInnerChannelFactory(); 
     } 

     public override IChannelListener BuildChannelListener(BindingContext context) 
     { 
      if (context == null) { 
       throw new ArgumentNullException("context"); 
      } 

      context.BindingParameters.Add(this); 
      return context.BuildInnerChannelListener(); 
     } 
 
+1

Je suis désolé si c'est une question stupide, mais où avez-vous placé ce code? Dans le proxy du client? Qu'en est-il du côté serveur? –

2

Avez-vous essayé de créer un CustomBinding à la place de la configuration NetTcpBinding dont vous disposez? Quelque chose comme ceci:

NetTcpBinding binding = new NetTcpBinding(); // get binding from somewhere 
var elements = binding.CreateBindingElements(); 
BindingElementCollection newElements = new BindingElementCollection(); 
foreach (var e in elements) { 
    if (e is MessageEncodingBindingElement) { 
     newElements.Add(new MyMessageEncodingBindingElement()); 
    } else { 
     newElements.Add(e); 
    } 
} 
CustomBinding cb = new CustomBinding(newElements); 
+1

J'ai aussi essayé cette méthode. La méthode CreateMessageEncoderFactory() n'est toujours pas appelée sur le LeanBinaryMessageEncodingBindingElement - le résultat est que mon codeur n'est pas construit du tout. Je dois manquer quelque chose d'évident. – Ajaxx

+0

Cela fonctionne dans .NET 4: D – markmnl

+0

@markmnl Ne fonctionne pas pour moi dans .Net 4.5.1 –

Questions connexes