次の方法で共有


カスタム メッセージ エンコーダ : カスタム テキスト エンコーダ

Download sample

このサンプルでは、Windows Communication Foundation (WCF) を使用してカスタム テキスト メッセージ エンコーダを実装する方法を示します。WCF の TextMessageEncodingBindingElement でサポートされているエンコーディングは、UTF-8、UTF-16、および Big Endean Unicode のみです。このサンプルのカスタム テキスト メッセージ エンコーダでは、すべてのプラットフォームでサポートされ、相互運用に必要とされる可能性のある文字エンコーディングがサポートされます。このサンプルは、クライアント コンソール プログラム (.exe)、インターネット インフォメーション サービス (IIS) によってホストされるサービス ライブラリ (.dll)、およびテキスト メッセージ エンコーダ ライブラリ (.dll) で構成されています。サービスは、要求/応答通信パターンを定義するコントラクトを実装します。このコントラクトは ICalculator インターフェイスによって定義されており、算術演算 (加算、減算、乗算、および除算) を公開しています。クライアントは指定された算術演算を同期要求し、サービスは結果と共に応答します。クライアントとサービスはどちらも、既定の TextMessageEncodingBindingElement の代わりに CustomTextMessageEncoder を使用します。

カスタム エンコーダの実装は、メッセージ エンコーダ ファクトリ、メッセージ エンコーダ、メッセージ エンコーディング バインディング要素、および構成ハンドラで構成され、次が示されます。

  • カスタム エンコーダおよびエンコーダ ファクトリの作成。

  • カスタム エンコーダのバインディング要素の作成。

  • カスタム バインディング要素を統合するためのカスタム バインディング構成の使用。

  • カスタム バインディング要素のファイル構成を可能にするカスタム構成ハンドラの開発。

サンプルを設定、ビルド、および実行するには

  1. Windows Communication Foundation サンプルの 1 回限りのセットアップの手順」が実行済みであることを確認します。

  2. ソリューションをビルドするには、「Windows Communication Foundation サンプルのビルド」の手順に従います。

  3. 単一コンピュータ構成か複数コンピュータ構成かに応じて、「Windows Communication Foundation サンプルの実行」の手順に従います。

メッセージ エンコーダ ファクトリとメッセージ エンコーダ

ServiceHost またはクライアント チャネルが開かれると、デザイン時コンポーネント CustomTextMessageBindingElementCustomTextMessageEncoderFactory を作成します。このファクトリは、CustomTextMessageEncoder を作成します。メッセージ エンコーダは、ストリーミング モードとバッファ モードの両方で動作し、XmlReaderXmlWriter を使用してメッセージの読み取りと書き込みを行います。UTF-8、UTF-16、および Big-Endean Unicode だけをサポートするように最適化された WCF の XML リーダーとライタとは異なり、これらのリーダーとライタはプラットフォームでサポートされるすべてのエンコーディングをサポートします。

カスタム テキスト メッセージ エンコーダのコード例を次に示します。

    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();
        }
    }

メッセージ エンコーダ ファクトリを作成する方法を次のコード例に示します。

    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;
            }
        }
    }

メッセージ エンコーディング バインディング要素

このバインディング要素により、WCF ランタイム スタックの構成が可能になります。WCF アプリケーション内でカスタム メッセージ エンコーダを使用するには、ランタイム スタックの適切なレベルで適切な設定を使用してメッセージ エンコーダ ファクトリを作成する、バインディング要素が必要です。

CustomTextMessageBindingElementBindingElement 基本クラスから派生し、MessageEncodingBindingElement クラスを継承します。これによって、他の WCF コンポーネントは、このバインディング要素をメッセージ エンコーディング バインディング要素として認識できます。CreateMessageEncoderFactory を実装すると、一致するメッセージ エンコーダ ファクトリのインスタンスが適切に設定されて返されます。

CustomTextMessageBindingElement は、プロパティを介して MessageVersionContentType、および Encoding の設定を公開します。エンコーダは、Soap11Addressing と Soap12Addressing1 の両方のバージョンをサポートします。既定は Soap11Addressing1 です。また、ContentType の既定値は "text/xml" です。Encoding プロパティでは、必要な文字エンコーディングの値を設定できます。サンプルのクライアントとサービスでは、ISO-8859-1 (Latin1) 文字エンコーディングを使用します。この規格は、WCF の TextMessageEncodingBindingElement ではサポートされません。

カスタム テキスト メッセージ エンコーダを使用してプログラムでバインディングを作成する方法を次のコードに示します。

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);

メッセージ エンコーディング バインディング要素へのメタデータのサポートの追加

MessageEncodingBindingElement から派生するすべての型は、サービスに対して生成される WSDL ドキュメント内の SOAP バインディングのバージョンを更新します。これを行うには、IWsdlExportExtension インターフェイス上に ExportEndpoint メソッドを実装し、生成された WSDL を変更します。このサンプルでは、CustomTextMessageBindingElementTextMessageEncodingBinidngElement からの WSDL エクスポート ロジックを使用します。

このサンプルの場合、クライアント構成は手動構成です。Svcutil.exe を使用してクライアント構成を生成することはできません。CustomTextMessageBindingElement では、動作を記述するポリシー アサーションがエクスポートされないからです。通常は、カスタム バインディング要素上に IPolicyExportExtension インターフェイスを実装して、バインディング要素によって実装される動作または機能を記述するカスタム ポリシー アサーションをエクスポートする必要があります。カスタム バインディング要素のポリシー アサーションをエクスポートする方法の例については、「トランスポート: UDP」サンプルを参照してください。

メッセージ エンコーディング バインディング構成ハンドラ

前のセクションでは、カスタム テキスト メッセージ エンコーダをプログラムによって使用する方法を示しました。CustomTextMessageEncodingBindingSection は構成ハンドラを実装します。この構成ハンドラにより、カスタム テキスト メッセージ エンコーダを構成ファイル内で使用することを指定できます。CustomTextMessageEncodingBindingSection クラスは BindingElementExtensionElement クラスから派生します。BindingElementType プロパティでは、このセクション用に作成するバインディング要素の型が構成システムに通知されます。

CustomTextMessageBindingElement によって定義されたすべての設定は、CustomTextMessageEncodingBindingSection のプロパティとして公開されます。ConfigurationPropertyAttribute は、構成要素の属性をプロパティにマップしたり、属性がない場合は既定値を設定する際に役立ちます。構成から値が読み込まれて型のプロパティに適用されると、CreateBindingElement メソッドが呼び出されます。このメソッドは、プロパティをバインディング要素の具体的なインスタンスに変換します。

この構成ハンドラは、サービスまたはクライアントの App.config または Web.config の次の表現にマップされます。

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

このサンプルでは、ISO-8859-1 エンコーディングを使用します。

この構成ハンドラを使用するには、次の構成要素を使用して登録する必要があります。

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

Footer image

Copyright © 2007 by Microsoft Corporation.All rights reserved.