Partager via


Custom Message Encoder: Custom Text Encoder

Cet exemple montre comment implémenter un codeur de message texte personnalisé à l'aide de Windows Communication Foundation (WCF). Le TextMessageEncodingBindingElement de WCF prend uniquement en charge les codages UTF-8, UTF-16 et Unicode Big-Endian. Le codeur de message texte personnalisé de cet exemple prend en charge l'ensemble des codages de caractères pris en charge par la plateforme qui peuvent s'avérer nécessaires pour l'interopérabilité. L'exemple se compose d'un programme de console client (.exe), d'une bibliothèque de service (.dll) hébergée par les services IIS (Internet Information Services) et d'une bibliothèque de codeurs de message texte (.dll). Le service implémente un contrat qui définit un modèle de communication demande-réponse. Le contrat est défini par l'interface ICalculator, laquelle expose les opérations mathématiques suivantes : addition, soustraction, multiplication et division. Le client adresse des demandes synchrones à une opération mathématique donnée et le service répond avec le résultat. Le client et le service utilisent CustomTextMessageEncoder au lieu du TextMessageEncodingBindingElement par défaut.

L'implémentation de codeur personnalisée se compose d'une fabrique de codeur de message, d'un codeur de message, d'un élément de liaison de codage de message et d'un gestionnaire de configuration, et présente les éléments suivants :

  • Création d'un codeur personnalisé et d'une fabrique de codeur.
  • Création d'un élément de liaison pour un codeur personnalisé.
  • Utilisation de la configuration de liaison personnalisée permettant d'intégrer des éléments de liaison personnalisés.
  • Développement d'un gestionnaire de configuration personnalisé afin de permettre la configuration de fichier d'un élément de liaison personnalisé.

Pour configurer, générer et exécuter l'exemple

  1. Assurez-vous d'avoir effectué la procédure indiquée dans la section Procédure d'installation unique pour les exemples Windows Communication Foundation.

  2. Pour générer la solution, suivez les instructions indiquées dans Génération des exemples Windows Communication Foundation.

  3. Pour exécuter l'exemple dans une configuration à un ou plusieurs ordinateurs, suivez les instructions indiquées dans Exécution des exemples Windows Communication Foundation.

Fabrique de codeur de message et codeur de message

Lorsque ServiceHost ou le canal client est ouvert, le composant au moment du design CustomTextMessageBindingElement crée CustomTextMessageEncoderFactory. La fabrique crée CustomTextMessageEncoder. Le codeur de message fonctionne à la fois en mode de diffusion en continu et en mode de mise en mémoire tampon. Il utilise XmlReader et XmlWriter pour respectivement lire et écrire les messages. Contrairement aux enregistreurs et lecteurs XML optimisés de WCF qui prennent uniquement en charge UTF-8, UTF-16 et Unicode Big-Endian, ces lecteurs et enregistreurs prennent en charge l'ensemble des codages de caractères pris en charge par la plateforme.

L'exemple de code suivant présente CustomTextMessageEncoder.

    public class CustomTextMessageEncoder : MessageEncoder
    {
        private CustomTextMessageEncoderFactory factory;
        private XmlWriterSettings writerSettings;
        private string contentType;
        
        public CustomTextMessageEncoder(CustomTextMessageEncoderFactory factory)
        {
            this.factory = factory;
            
            this.writerSettings = new XmlWriterSettings();
            this.writerSettings.Encoding = Encoding.GetEncoding(factory.CharSet);
            this.contentType = string.Format("{0}; charset={1}", 
                this.factory.MediaType, this.writerSettings.Encoding.HeaderName);
        }

        public override string ContentType
        {
            get
            {
                return this.contentType;
            }
        }

        public override string MediaType
        {
            get 
            {
                return factory.MediaType;
            }
        }

        public override MessageVersion MessageVersion
        {
            get 
            {
                return this.factory.MessageVersion;
            }
        }

        public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
        {   
            byte[] msgContents = new byte[buffer.Count];
            Array.Copy(buffer.Array, buffer.Offset, msgContents, 0, msgContents.Length);
            bufferManager.ReturnBuffer(buffer.Array);

            MemoryStream stream = new MemoryStream(msgContents);
            return ReadMessage(stream, int.MaxValue);
        }

        public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
        {
            XmlReader reader = XmlReader.Create(stream);
            return Message.CreateMessage(reader, maxSizeOfHeaders, this.MessageVersion);
        }

        public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
        {
            MemoryStream stream = new MemoryStream();
            XmlWriter writer = XmlWriter.Create(stream, this.writerSettings);
            message.WriteMessage(writer);
            writer.Close();
            
            byte[] messageBytes = stream.GetBuffer();
            int messageLength = (int)stream.Position;
            stream.Close();

            int totalLength = messageLength + messageOffset;
            byte[] totalBytes = bufferManager.TakeBuffer(totalLength);
            Array.Copy(messageBytes, 0, totalBytes, messageOffset, messageLength);

            ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, messageOffset, messageLength);
            return byteArray;
        }

        public override void WriteMessage(Message message, Stream stream)
        {
            XmlWriter writer = XmlWriter.Create(stream, this.writerSettings);
            message.WriteMessage(writer);
            writer.Close();
        }
    }

L'exemple de code suivant montre comment créer la fabrique de codeur de message.

    public class CustomTextMessageEncoderFactory : MessageEncoderFactory
    {
        private MessageEncoder encoder;
        private MessageVersion version;
        private string mediaType;
        private string charSet;

        internal CustomTextMessageEncoderFactory(string mediaType, string charSet,
            MessageVersion version)
        {
            this.version = version;
            this.mediaType = mediaType;
            this.charSet = charSet;
            this.encoder = new CustomTextMessageEncoder(this);
        }

        public override MessageEncoder Encoder
        {
            get 
            { 
                return this.encoder;
            }
        }

        public override MessageVersion MessageVersion
        {
            get 
            { 
                return this.version;
            }
        }

        internal string MediaType
        {
            get
            {
                return this.mediaType;
            }
        }

        internal string CharSet
        {
            get
            {
                return this.charSet;
            }
        }
    }

Élément de liaison de codage de message

Les éléments de liaison permettent de configurer la pile d'exécution WCF. Pour utiliser le codeur de message personnalisé dans une application WCF, un élément de liaison est requis et permet de créer la fabrique de codeur de message avec les paramètres appropriés au niveau correct dans la pile d'exécution.

CustomTextMessageBindingElement dérive de la classe de base BindingElement et hérite de la classe MessageEncodingBindingElement. Cela permet à d'autres composants WCF de reconnaître cet élément de liaison comme étant un élément de liaison de codage de message. L'implémentation de CreateMessageEncoderFactory retourne une instance de la fabrique de codeur de message correspondante avec les paramètres appropriés.

CustomTextMessageBindingElement expose des paramètres pour MessageVersion, ContentTypeet Encoding via des propriétés. Le codeur prend en charge les versions Soap11Addressing et Soap12Addressing1. La valeur par défaut est Soap11Addressing1. La valeur par défaut de ContentType est "text/xml". La propriété Encoding vous permet de définir la valeur du codage de caractères souhaité. L'exemple de client et de service utilise le codage de caractères ISO-8859-1 (Latin1), qui n'est pas pris en charge par le TextMessageEncodingBindingElement de WCF.

Le code suivant montre comment créer la liaison par programme à l'aide du codeur de message texte personnalisé.

ICollection<BindingElement> bindingElements = new List<BindingElement>();
HttpTransportBindingElement httpBindingElement = new HttpTransportBindingElement();
CustomTextMessageBindingElement textBindingElement = new CustomTextMessageBindingElement();
bindingElements.Add(textBindingElement);
bindingElements.Add(httpBindingElement);
CustomBinding binding = new CustomBinding(bindingElements);

Ajout de la prise en charge des métadonnées à l'élément de liaison de codage de message

Les types qui dérivent de MessageEncodingBindingElement sont chargés de mettre à jour la version de la liaison SOAP dans le document WSDL généré pour le service. Pour ce faire, implémentez la méthode ExportEndpoint sur l'interface IWsdlExportExtension, puis modifiez le document WSDL généré. Dans cet exemple, CustomTextMessageBindingElement utilise la logique d'exportation WSDL de TextMessageEncodingBinidngElement.

Pour cet exemple, la configuration du client est créée manuellement. Vous ne pouvez pas utiliser Svcutil.exe pour générer la configuration du client car CustomTextMessageBindingElement n'exporte pas d'assertion de stratégie pour décrire son comportement. Il est en général préférable d'implémenter l'interface IPolicyExportExtension sur un élément de liaison personnalisé pour exporter une assertion de stratégie personnalisée qui décrit le comportement ou la fonctionnalité implémentée par l'élément de liaison. Pour obtenir un exemple d'exportation d'assertion de stratégie pour un élément de liaison personnalisé, consultez l'exemple Transport: UDP.

Gestionnaire de configuration de liaison de codage de message

La section précédente montre comment utiliser le codeur de message texte personnalisé par programme. CustomTextMessageEncodingBindingSection implémente un gestionnaire de configuration qui vous permet de spécifier l'utilisation d'un codeur de message texte personnalisé dans un fichier de configuration. La classe CustomTextMessageEncodingBindingSection dérive de la classe BindingElementExtensionElement. La propriété BindingElementType indique au système de configuration le type d'élément de liaison à créer pour cette section.

Tous les paramètres définis par CustomTextMessageBindingElement sont exposés en tant que propriétés dans CustomTextMessageEncodingBindingSection. ConfigurationPropertyAttribute permet de mapper les attributs d'élément de configuration aux propriétés et d'affecter des valeurs par défaut si les attributs ne sont pas définis. Après avoir chargé et appliqué les valeurs de la configuration aux propriétés du type, la méthode CreateBindingElement est appelée et convertit les propriétés en instance concrète d'un élément de liaison.

Ce gestionnaire de configuration mappe à la représentation suivante dans le fichier App.config ou Web.config du service ou du client.

<customTextMessageEncoding encoding="utf-8" contentType="text/xml" messageVersion="Soap11Addressing1" />

L'exemple utilise le codage ISO-8859-1.

Pour utiliser ce gestionnaire de configuration, il doit être enregistré à l'aide de l'élément de configuration suivant.

<extensions>
    <bindingElementExtensions>
        <add name="customTextMessageEncoding" type=" 
Microsoft.ServiceModel.Samples.CustomTextMessageEncodingBindingSection, 
                  CustomTextMessageEncoder" />
    </bindingElementExtensions>
</extensions>

Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.