次の方法で共有


サービスの説明とプロキシ クラスの生成のカスタマイズ

ASP.NET を使用して作成した XML Web サービスのサービスの説明とプロキシ クラスの生成は、サービスの説明形式拡張機能 (SDFE: Service Description Format Extension) を作成しインストールすることによって拡張できます。具体的には、SDFE によってサービスの説明 (XML Web サービスの WSDL ドキュメント) に XML 要素を追加し、XML Web サービスと通信するメソッドにカスタム属性を追加できます。

SDFE は、特に XML Web サービスとそのクライアントの両方で SOAP 拡張機能を実行する必要がある場合に便利です。既定では、SOAP 拡張機能に関する情報は、サービスの説明とサービスの説明について生成されたプロキシ クラスのどちらにも配置されません。クライアントとサーバーの両方で実行する必要がある SOAP 拡張機能の例としては、暗号化 SOAP 拡張機能があります。サーバー上の暗号化 SOAP 拡張機能が SOAP 応答を暗号化する場合、クライアントにはメッセージの復号化を実行する SOAP 拡張機能が必要です。SDFE によって SOAP 拡張機能を実行する必要があることをクライアントに通知する要素をサービスの説明に追加できます。また、SDFE によってプロキシ クラスの生成処理を拡張してプロキシ クラスにカスタム属性を追加し、クラスで SOAP 拡張機能が実行できます。

SDFE を作成する基本手順は次のとおりです。

  1. サービスの説明に追加する XML を定義します。
  2. サービスの説明の生成処理を拡張するコードを記述します。
  3. プロキシ クラスの生成処理を拡張するコードを記述します。
  4. SDFE がクライアントとサーバーの両方で実行されるように構成します。

各手順の詳しい説明と操作手順を次に示します。

サービスの説明に追加する XML を定義するには

  1. サービスの説明に追加する XML を決定します。

    サンプル SDFE で XML 要素を追加するサービスの説明の部分的なコード例を次に示します。具体的には、このサンプル SDFE は XML 名前空間プリフィックス yml<definitions> 要素に追加し、<yml:action> 要素に格納されるこの要素を SOAP バインディングの <operation> 要素に追加します。

    <definitions ...
      xmlns:yml="https://www.contoso.com/yml" >
      ...
      <binding name="HelloWorldSoap" type="s0:HelloWorldSoap">
        <soap:binding transport="https://schemas.xmlsoap.org/soap/http"
                    style="document" /> 
          <operation name="SayHello">
            <soap:operation soapAction="http://tempuri.org/SayHello"
                        style="document" />
            <yml:action>          <yml:Reverse>true</yml:Reverse>         </yml:action>
          </operation>
          ...
      </binding>
      ... 
    </definitions>
    
  2. ServiceDescriptionFormatExtension から派生するクラスを作成します。

    Visual Studio .NET を使用している場合は、System.Web.Services アセンブリへの参照を追加します。また、System.Web.Services.Description 名前空間の using ステートメントまたは Imports ステートメントをファイルに追加します。ServiceDescriptionFormatExtension から派生した TraceOperationBinding クラスを作成するコード例を次に示します。

    Public Class YMLOperationBinding
        Inherits ServiceDescriptionFormatExtension
    [C#]
    public class YMLOperationBinding : ServiceDescriptionFormatExtension
    
  3. 作成したクラスに XmlFormatExtensionAttribute を適用します。

    この属性は、サービスの説明の生成処理で、SDFE が実行される段階 (拡張ポイント) を指定します。定義済みの拡張ポイントと各ポイントで生成されるサービスの説明の XML 要素の一覧を次に示します。

    拡張ポイント 説明
    ServiceDescription WSDL ドキュメントの <definitions> ルート要素に相当します。
    Types <definitions> ルート要素で囲まれた <types> 要素に相当します。
    Binding <definitions> ルート要素で囲まれた <binding> 要素に相当します。
    OperationBinding <binding> 要素で囲まれた <operation> 要素に相当します。
    InputBinding <operation> 要素で囲まれた <input> 要素に相当します。
    OutputBinding <operation> 要素で囲まれた <output> 要素に相当します。
    FaultBinding <operation> 要素で囲まれた <fault> 要素に相当します。
    Port <service> 要素で囲まれた <port> 要素に相当します。
    Operation <portType> 要素で囲まれた <operation> 要素に相当します。

    クラスに XmlFormatExtensionAttribute を適用する場合は、XML 要素と、サービスの説明に追加する XML 要素を格納する XML 名前空間も指定します。

    YMLOperationBinding SDFE が <action xmlns="https://www.contoso.com/yml"> という名前の XML 要素を、OperationBinding 拡張ポイントでサービスの説明に追加することを指定するコード例を次に示します。この例では、後で TraceOperationBinding.YMLNamespace フィールドがクラスに追加されたときに、XML 名前空間 https://www.contoso.com/yml が指定されます。

    <XmlFormatExtension("action", YMLOperationBinding.YMLNamespace, _
                        GetType(OperationBinding))> _
    Public Class YMLOperationBinding
        Inherits ServiceDescriptionFormatExtension 
    [C#]
    [XmlFormatExtension("action", YMLOperationBinding.YMLNamespace,
                        typeof(OperationBinding))]
    public class YMLOperationBinding : ServiceDescriptionFormatExtension
    
  4. クラスに XmlFormatExtensionPrefixAttribute を適用して、XML 名前空間プリフィックスを SDFE で使用される XML 名前空間に関連付けることもできます。

    yml XML 名前空間プリフィックスを、サービスの説明の <definitions> 要素内の https://www.contoso.com/yml 名前空間に関連付けることを指定するコード例を次に示します。さらに、SDFE によって追加された要素内で、名前空間の代わりにプリフィックスが使用されています。したがって、手順 3 でサービスの説明に追加された XML 要素は名前空間プリフィックスを使用することになるので、追加する要素は <action xmlns="https://www.contoso.com/yml"> ではなく <yml:action> です。

    <XmlFormatExtension("action", YMLOperationBinding.YMLNamespace, _
                        GetType(OperationBinding)), _
     XmlFormatExtensionPrefix("yml", YMLOperationBinding.YMLNamespace)> _
    Public Class YMLOperationBinding
         Inherits ServiceDescriptionFormatExtension 
    [C#]
    [XmlFormatExtension("action", YMLOperationBinding.YMLNamespace,
                        typeof(OperationBinding))]
    [XmlFormatExtensionPrefix("yml", YMLOperationBinding.YMLNamespace)]
    public class YMLOperationBinding : ServiceDescriptionFormatExtension 
    
  5. サービスの説明に追加する XML を表すクラスに、パブリック プロパティまたはフィールドを追加します。サービスの説明の <yml:Reverse>value</yml:Reverse> 要素にシリアル化される Reverse パブリック プロパティを追加するコード例を次に示します。

    Private _reverse As Boolean
    <XmlElement("Reverse")> _
    Public Property Reverse() As Boolean
       Get
         Return _reverse
       End Get
       Set(ByVal Value As Boolean)
          _reverse = Value
       End Set
    End Property 
    [C#]
    private Boolean reverse;
    [XmlElement("Reverse")]
    public Boolean Reverse 
    {
       get { return reverse; }
       set { reverse = value; }
    }
    

サービスの説明の生成処理を拡張するには

  1. SoapExtensionReflector から派生するクラスを作成します。

    SoapExtensionReflector から派生した TraceReflector クラスを作成するコード例を次に示します。

    Public Class YMLReflector
        Inherits SoapExtensionReflector
    [C#]
    public class YMLReflector : SoapExtensionReflector
    
  2. 各 XML Web サービス メソッドについて、サービスの説明の生成時に呼び出される ReflectMethod メソッドをオーバーライドします。

    ReflectMethod をオーバーライドするコード例を次に示します。

    Public Overrides Sub ReflectMethod()
    [C#]
    public override void ReflectMethod()
    
  3. SoapExtensionReflector クラスの ReflectionContext プロパティの値を取得して、ProtocolReflector のインスタンスを取得します。

    ProtocolReflector のインスタンスは、現在の XML Web サービス メソッドの WSDL 生成処理の詳細を提供します。ReflectionContext プロパティの値を取得するコード例を次に示します。

    Dim reflector As ProtocolReflector = ReflectionContext
    [C#]
    ProtocolReflector reflector = ReflectionContext;
    
  4. SDFE にコードを追加します。

    YMLAttribute を XML Web サービス メソッドに適用する場合に、SDFE によって定義された XML をサービスの説明に追加するコード例を次に示します。

    Dim attr As YMLAttribute = _
        reflector.Method.GetCustomAttribute(GetType(YMLAttribute))
    ' If the YMLAttribute has been applied to this XML Web service
    ' method, adds the XML defined in the YMLOperationBinding class.
    If (Not attr Is Nothing) Then
       Dim yml As YMLOperationBinding = New YMLOperationBinding()
       yml.Reverse = Not attr.Disabled 
    [C#]
    YMLAttribute attr = (YMLAttribute)
       reflector.Method.GetCustomAttribute(typeof(YMLAttribute));
    // If the YMLAttribute has been applied to this XML Web service 
    // method, adds the XML defined in the YMLOperationBinding class.
    if (attr != null) {
       YMLOperationBinding yml = new YMLOperationBinding();
       yml.Reverse = !(attr.Disabled);
    
  5. SDFE が拡張する拡張ポイントを表すプロパティの Extensions コレクションに SDFE を追加します。

    TraceOperationBinding SDFE を OperationBinding 拡張ポイントに追加するコード例を次に示します。

    reflector.OperationBinding.Extensions.Add(yml)
    [C#]
    reflector.OperationBinding.Extensions.Add(yml);
    

プロキシ クラスの生成処理を拡張するには

  1. SoapExtensionImporter から派生するクラスを作成します。

    Public Class YMLImporter
        Inherits SoapExtensionImporter 
    [C#]
    public class YMLImporter : SoapExtensionImporter
    
  2. ImportMethod メソッドをオーバーライドします。

    ImportMethod は、サービスの説明で定義されている各操作のプロキシ クラスの生成時に呼び出されます。ASP.NET を使用して作成した XML Web サービスの場合は、各 XML Web サービス メソッドがサービスの説明内のサポートされている各プロトコルに割り当てられます。

    Public Overrides Sub ImportMethod(ByVal metadata As _
                                      CodeAttributeDeclarationCollection)
    [C#]
    public override void ImportMethod(CodeAttributeDeclarationCollection
                                      metadata)   
    
  3. SoapExtensionImporterImportContext プロパティの値を取得して、SoapProtocolImporter のインスタンスを取得します。

    SoapProtocolImporter のインスタンスは、XML Web サービス メソッドと通信している現在のメソッドのコード生成処理に関する詳細を提供します。ImportContext プロパティの値を取得するコード例を次に示します。

    Dim importer As SoapProtocolImporter = ImportContext
    [C#]
    SoapProtocolImporter importer = ImportContext;  
    
  4. XML Web サービスと通信するプロキシ クラスのメソッドに、属性を適用または変更するコードを追加します。

    ImportMethodCodeAttributeDeclarationCollection 型の引数を 1 つ渡します。この引数は、XML Web サービス メソッドと通信するメソッドに適用される属性のコレクションを表します。YMLAttribute をコレクションに追加し、適切な XML がサービスの説明に含まれる場合に YML SOAP 拡張機能がメソッドと共に実行されるようにするコード例を次に示します。

    ' Checks whether the XML specified in the YMLOperationBinding is in the
    ' service description.
    Dim yml As YMLOperationBinding = _
      importer.OperationBinding.Extensions.Find( _
      GetType(YMLOperationBinding))
    If (Not yml Is Nothing) Then
       ' Only applies the YMLAttribute to the method when the XML should
       ' be reversed.
       If (yml.Reverse) Then
          Dim attr As CodeAttributeDeclaration = New _
            CodeAttributeDeclaration(GetType(YMLAttribute).FullName)
          attr.Arguments.Add(New CodeAttributeArgument(New _
               CodePrimitiveExpression(True)))
          metadata.Add(attr)
       End If
    End If
    [C#]
    // Checks whether the XML specified in the YMLOperationBinding is
    // in the service description.
    YMLOperationBinding yml = (YMLOperationBinding)
       importer.OperationBinding.Extensions.Find(
       typeof(YMLOperationBinding));
    if (yml != null)
    {
       // Only applies the YMLAttribute to the method when the XML should
       // be reversed.
       if (yml.Reverse)
       {
         CodeAttributeDeclaration attr = new
            CodeAttributeDeclaration(typeof(YMLAttribute).FullName);
         attr.Arguments.Add(new CodeAttributeArgument(new
            CodePrimitiveExpression(true)));
         metadata.Add(attr);
       }
    }
    

SDFE が XML Web サービスと共に実行されるように構成するには

  1. SDFE を含むアセンブリをアクセス可能なフォルダにインストールします。

    SDFE が複数の Web アプリケーションで必要である場合以外は、XML Web サービスを管理する Web アプリケーションの \Bin フォルダに SDFE をインストールします。

  2. SDFE の名前および SDFE を含むアセンブリを指定する <add> 要素を持つ <serviceDescriptionFormatExtensionTypes> 要素を、Web アプリケーションの Web.config ファイルに追加します。

    Sample.YMLOperationBinding SDFE を、Web.config ファイルの影響を受けるすべての XML Web サービスと共に実行するように構成するコード例を次に示します。実際の <add> 要素は 1 行に記述する必要があります。

    <system.web>
       <webServices>
          <serviceDescriptionFormatExtensionTypes>         <add type="Sample.YMLOperationBinding,Yml,              Version=1.0.0.0,Culture=neutral,              PublicKeyToken=6e55c64c6b897b30"/>      </serviceDescriptionFormatExtensionTypes>
       </webServices>
    </system.web>
    
  3. サービスの説明の生成処理を拡張するクラスの名前およびアセンブリ指定する <add> 要素を持つ <soapExtensionReflectorTypes> 要素を、Web アプリケーションの Web.config ファイルに追加します。

    Sample.YMLReflector を、Web.config ファイルの影響を受けるすべての XML Web サービスと共に実行するように構成するコード例を次に示します。実際の <add> 要素は 1 行に記述する必要があります。

    <system.web>
       <webServices>
          <serviceDescriptionFormatExtensionTypes>
             <add type="Sample.YMLOperationBinding,Yml,              Version=1.0.0.0,Culture=neutral,              PublicKeyToken=6e55c64c6b897b30"/>
          </serviceDescriptionFormatExtensionTypes>
          <soapExtensionReflectorTypes>         <add type="Sample.YMLReflector,Yml,              Version=1.0.0.0,Culture=neutral,              PublicKeyToken=6e55c64c6b897b30"/>      </soapExtensionReflectorTypes>
       </webServices>
    </system.web>
    

SDFE が XML Web サービス クライアントと共に実行されるように構成するには

  1. SDFE を含むアセンブリをグローバル アセンブリ キャッシュにインストールします。

    インストールするためには、アセンブリに厳密な名前を割り当てる必要があります。厳密な名前を割り当てたアセンブリの作成の詳細については、「厳密な名前付きアセンブリの作成と使用」を参照してください。アセンブリのインストールの詳細については、「グローバル アセンブリ キャッシュへのアセンブリのインストール」を参照してください。

  2. SDFE の名前および SDFE を含むアセンブリを指定する <add> 要素を持つ <serviceDescriptionFormatExtensionTypes> 要素を、Machine.config ファイルに追加します。

    マシン上で XML Web サービスについてプロキシ クラスが生成されるたびに実行されるように Sample.YMLOperationBinding SDFE を構成するコード例を次に示します。

    <system.web>
       <webServices>
          <serviceDescriptionFormatExtensionTypes>         <add type="Sample.YMLOperationBinding,Yml,              Version=1.0.0.0,Culture=neutral,              PublicKeyToken=6e55c64c6b897b30"/>      </serviceDescriptionFormatExtensionTypes>
       </webServices>
    </system.web>
    
  3. プロキシ クラスの生成処理を拡張するクラスの名前とアセンブリ指定する <add> 要素を持つ <soapExtensionImporterTypes> 要素を、Machine.config ファイルに追加します。

    マシン上で XML Web サービスについてプロキシ クラスが生成されるたびに実行されるように Sample.YMLImporter を構成するコード例を次に示します。

    <system.web>
       <webServices>
          <serviceDescriptionFormatExtensionTypes>
             <add type="Sample.YMLOperationBinding,Yml,              Version=1.0.0.0,Culture=neutral,              PublicKeyToken=6e55c64c6b897b30"/>
          </serviceDescriptionFormatExtensionTypes>
          <soapExtensionImporterTypes>         <add type="Sample.YMLImporter,Yml,              Version=1.0.0.0,Culture=neutral,              PublicKeyToken=6e55c64c6b897b30"/>      </soapExtensionImporterTypes>
       </webServices>
    </system.web>
    

    **メモ   **プロキシ クラスで生成されたメソッドは、XML Web サービスと通信するクライアント アプリケーションによって使用されるので、クライアント アプリケーションで認識できないアセンブリ内にある属性を SDFE が追加する場合は、コンパイラ エラーが生成されます。このコンパイラ エラーを解決するには、Visual Studio .NET を使用している場合は、属性を含むアセンブリへの参照を追加します。コマンド ライン コンパイルを実行している場合は、コンパイラのコマンド ラインにアセンブリを追加します。

完全な SDFE のサンプル コード

YML SOAP 拡張機能に関する詳細を含むようにサービスの説明とプロキシの生成処理を拡張する SDFE のコード例を次に示します。

Imports System
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.IO
Imports System.Text
Imports System.Web.Services.Configuration
Imports System.Web.Services.Description
Imports System.Xml.Serialization
Imports System.CodeDom

' The YMLAttribute allows a developer to specify that the YML SOAP
' extension run on a per-method basis.  The disabled property
' turns reversing the XML on and off. 
<AttributeUsage(AttributeTargets.Method, AllowMultiple:=False)> _
Public Class YMLAttribute
    Inherits SoapExtensionAttribute
    Dim _priority As Integer = 0
    Dim _disabled As Boolean = False

    Public Sub New()
        Me.New(False)
    End Sub
    Public Sub New(ByVal Disabled As Boolean)
        _disabled = Disabled
    End Sub
    Public Overrides ReadOnly Property ExtensionType() As Type
        Get
            Return GetType(YMLExtension)
        End Get
    End Property
    Public Overrides Property Priority() As Integer
        Get
            Return _priority
        End Get
        Set(ByVal Value As Integer)
            _priority = Value
        End Set
    End Property

    Public Property Disabled() As Boolean
        Get
            Return _disabled
        End Get
        Set(ByVal Value As Boolean)
            _disabled = Value
        End Set
    End Property
End Class

Public Class YMLExtension
    Inherits SoapExtension
    Dim _disabled As Boolean = False
    Dim oldStream As Stream
    Dim newStream As Stream

    Public Overloads Overrides Function GetInitializer(ByVal methodInfo _
                   As LogicalMethodInfo, _
                   ByVal attribute As SoapExtensionAttribute) As Object
        Dim attr As YMLAttribute = attribute
        If (Not attr Is Nothing) Then
            Return attr.Disabled
        End If
        Return False
    End Function

    Public Overloads Overrides Function GetInitializer(ByVal _
      WebServiceType As Type) As Object
        Return False
    End Function

    Public Overrides Sub Initialize(ByVal initializer As Object)
        If (TypeOf initializer Is Boolean) Then
            _disabled = CBool(initializer)
        End If
    End Sub

    Public Overrides Function ChainStream(ByVal streamref As Stream) _
      As Stream
        If (_disabled) Then
            Return CType(Me, SoapExtension).ChainStream(streamref)
        End If
        oldStream = streamref
        newStream = New MemoryStream()
        Return newStream
    End Function

    Public Overrides Sub ProcessMessage(ByVal message As SoapMessage)
        If (_disabled) Then Return
        Select Case (message.Stage)
            Case SoapMessageStage.BeforeSerialize
                Encode(message)
            Case SoapMessageStage.AfterSerialize
                newStream.Position = 0
                Reverse(newStream, oldStream)
            Case SoapMessageStage.BeforeDeserialize
                Decode(message)
            Case SoapMessageStage.AfterDeserialize
        End Select
    End Sub

    Sub Encode(ByRef message As SoapMessage)
        message.ContentType = "text/yml"
    End Sub

    Sub Decode(ByVal message As SoapMessage)
        If (message.ContentType <> "text/yml") Then
            Throw New Exception("invalid content type:" + _
                                 message.ContentType)
        End If
        Reverse(oldStream, newStream)
        newStream.Position = 0
        message.ContentType = "text/xml"
    End Sub

    Sub Reverse(ByVal source As Stream, ByVal dest As Stream)
        Dim reader As TextReader = New StreamReader(source)
        Dim writer As TextWriter = New StreamWriter(dest)
        Dim line As String
        line = reader.ReadLine()
        While (Not line Is Nothing)
            writer.WriteLine(StrReverse(line))
            line = reader.ReadLine()
        End While
        writer.Flush()
    End Sub
End Class

' The YMLReflector class is part of the YML SDFE; it is
' called during the service description generation process.
Public Class YMLReflector
    Inherits SoapExtensionReflector
    Public Overrides Sub ReflectMethod()
        Dim reflector As ProtocolReflector = ReflectionContext
        Dim attr As YMLAttribute = _
            reflector.Method.GetCustomAttribute(GetType(YMLAttribute))
        ' If the YMLAttribute has been applied to this XML Web service 
        ' method, adds the XML defined in the YMLOperationBinding class.
        If (Not attr Is Nothing) Then
            Dim yml As YMLOperationBinding = New YMLOperationBinding()
            yml.Reverse = Not attr.Disabled
            reflector.OperationBinding.Extensions.Add(yml)
        End If
    End Sub
End Class

' The YMLImporter class is part of the YML SDFE; it is called when
' a proxy class is generated for each XML Web service method the proxy
' class communicates with.  The class checks whether the service
' description contains the XML that this SDFE adds to a service
' description.  If it exists, then the YMLExtension is applied to the
' method in the proxy class.
Public Class YMLImporter
    Inherits SoapExtensionImporter
    Public Overrides Sub ImportMethod(ByVal metadata As _
                           CodeAttributeDeclarationCollection)
      Dim importer As SoapProtocolImporter = ImportContext
      ' Checks whether the XML specified in the YMLOperationBinding is 
      ' in the service description.
      Dim yml As YMLOperationBinding = _
        importer.OperationBinding.Extensions.Find(
        GetType(YMLOperationBinding))
      If (Not yml Is Nothing) Then
         ' Only applies the YMLAttribute to the method when the XML
         ' should be reversed.
         If (yml.Reverse) Then
            Dim attr As CodeAttributeDeclaration = New _
               CodeAttributeDeclaration(GetType(YMLAttribute).FullName)
            attr.Arguments.Add(New CodeAttributeArgument(New _
               CodePrimitiveExpression(True)))
            metadata.Add(attr)
         End If
       End If
    End Sub
End Class

' The YMLOperationBinding class is part of the YML SDFE; it is the
' class that is serialized into XML and placed in the service
' description.
<XmlFormatExtension("action", YMLOperationBinding.YMLNamespace, _
                     GetType(OperationBinding)), _
 XmlFormatExtensionPrefix("yml", YMLOperationBinding.YMLNamespace)> _
Public Class YMLOperationBinding
    Inherits ServiceDescriptionFormatExtension
    Private _reverse As Boolean
    Public Const YMLNamespace As String = "https://www.contoso.com/yml"

    <XmlElement("Reverse")> _
    Public Property Reverse() As Boolean
        Get
            Return _reverse
        End Get
        Set(ByVal Value As Boolean)
            _reverse = Value
        End Set
    End Property
End Class 
[C#]
using System;
using System.CodeDom;
using System.IO;
using System.Text;
using System.Web.Services.Configuration;
using System.Web.Services.Description;
using System.Web.Services.Protocols;
using System.Xml.Serialization;
 
// The YMLAttribute allows a developer to specify that the YML SOAP
// extension run on a per-method basis.  The disabled property
// turns reversing the XML on and off. 

[AttributeUsage(AttributeTargets.Method, AllowMultiple=false)]
public class YMLAttribute : SoapExtensionAttribute 
{
  int priority = 0;
  bool disabled = false;
       
  public YMLAttribute() : this(false) {}
  public YMLAttribute(bool disabled) 
  {
     this.disabled = disabled;
  }
      
  public override Type ExtensionType 
  {
    get { return typeof(YMLExtension); }
  }
  public override int Priority 
  {
    get { return priority; }
    set { priority = value; }
  }

  public bool Disabled 
  { 
    get { return disabled; }
    set { disabled = value; }
  }
}

public class YMLExtension : SoapExtension 
{
  bool disabled = false;
  Stream oldStream;
  Stream newStream;

  public override object GetInitializer(LogicalMethodInfo methodInfo,
                                        SoapExtensionAttribute attribute)
  {
    YMLAttribute attr = attribute as YMLAttribute;
    if (attr != null) return attr.Disabled;
       return false;
  }

  public override object GetInitializer(Type serviceType) 
  {
        return false;
  }

  public override void Initialize(object initializer) 
  {
     if (initializer is Boolean) disabled = (bool)initializer;
  }

  public override Stream ChainStream(Stream stream) 
  {
     if (disabled) return base.ChainStream(stream);
     oldStream = stream;
     newStream = new MemoryStream();
     return newStream;
  }

  public override void ProcessMessage(SoapMessage message) 
  {
    if (disabled) return;
    switch (message.Stage) 
    {
      case SoapMessageStage.BeforeSerialize:
        Encode(message);
        break;
      case SoapMessageStage.AfterSerialize:
        newStream.Position = 0;
        Reverse(newStream, oldStream);
        break;
      case SoapMessageStage.BeforeDeserialize:
        Decode(message);
        break;
      case SoapMessageStage.AfterDeserialize:
        break;
    }
  }        
  void Encode(SoapMessage message) 
  {
     message.ContentType = "text/yml";
  }

  void Decode(SoapMessage message) 
  {
   if (message.ContentType != "text/yml") 
     throw new Exception("invalid content type:" + message.ContentType);
   Reverse(oldStream, newStream);
   newStream.Position = 0;
   message.ContentType = "text/xml";
  }

  void Reverse(Stream from, Stream to) 
  {
    TextReader reader = new StreamReader(from);
    TextWriter writer = new StreamWriter(to);
    string line;
    while ((line = reader.ReadLine()) != null) 
    {
      StringBuilder builder = new StringBuilder();
      for (int i = line.Length - 1; i >= 0; i--) 
      {
        builder.Append(line[i]);
      }
      writer.WriteLine(builder.ToString());
    }
    writer.Flush();
  }
}

// The YMLReflector class is part of the YML SDFE; it is
// called during the service description generation process.
public class YMLReflector : SoapExtensionReflector 
{
  public override void ReflectMethod() 
  {
    ProtocolReflector reflector = ReflectionContext;
    YMLAttribute attr = (YMLAttribute)reflector.Method.GetCustomAttribute(
                        typeof(YMLAttribute));
    // If the YMLAttribute has been applied to this XML Web service
    // method, adds the XML defined in the YMLOperationBinding class.
    if (attr != null) 
    {
      YMLOperationBinding yml = new YMLOperationBinding();
      yml.Reverse = !(attr.Disabled);
      reflector.OperationBinding.Extensions.Add(yml);
    }
  }
}
  
// The YMLImporter class is part of the YML SDFE; it is called when
// a proxy class is generated for each XML Web service method the proxy
// class communicates with.  The class checks whether the service
// description contains the XML that this SDFE adds to a service
// description.  If it exists, then the YMLExtension is applied to the
// method in the proxy class.
public class YMLImporter : SoapExtensionImporter 
{
  public override void ImportMethod(CodeAttributeDeclarationCollection
                                    metadata)
 {
    SoapProtocolImporter importer = ImportContext;
   // Checks whether the XML specified in the YMLOperationBinding is in
   // the service description.
   YMLOperationBinding yml = (YMLOperationBinding)
       importer.OperationBinding.Extensions.Find(
       typeof(YMLOperationBinding));
   if (yml != null)
   {
     // Only applies the YMLAttribute to the method when the XML should
     // be reversed.
     if (yml.Reverse)
     {
       CodeAttributeDeclaration attr = new CodeAttributeDeclaration(
            typeof(YMLAttribute).FullName);
       attr.Arguments.Add(new CodeAttributeArgument(new
         CodePrimitiveExpression(true)));
       metadata.Add(attr);
     }
   }
 }
}

// The YMLOperationBinding class is part of the YML SDFE; it is the
// class that is serialized into XML and placed in the service
// description.
[XmlFormatExtension("action", YMLOperationBinding.YMLNamespace,
                    typeof(OperationBinding))]
[XmlFormatExtensionPrefix("yml", YMLOperationBinding.YMLNamespace)]
public class YMLOperationBinding : ServiceDescriptionFormatExtension 
{
   private Boolean reverse;
   public const string YMLNamespace = "https://www.contoso.com/yml";

   [XmlElement("Reverse")]
   public Boolean Reverse 
   {
     get { return reverse; }
     set { reverse = value; }
   }
}

参照

SOAP 拡張機能を使用した SOAP メッセージの変更 | XmlFormatExtensionAttribute | XmlFormatExtensionPrefixAttribute | XmlFormatExtensionPointAttribute