共用方式為


自訂服務描述和 Proxy 類別的產生

為使用 ASP.NET 所建立的 XML Web Service 產生服務描述和 Proxy 類別時,可藉由建立和安裝服務描述格式擴充功能 (Service Description Format Extension,SDFE) 來進行擴充。特別的是,SDFE 可以將 XML 項目加入至服務描述 (XML Web Service 的 WSDL 文件),然後將自訂屬性加入至與 XML Web Service 進行通訊的方法。

在 SOAP 擴充功能必須使用 XML Web Service 及其用戶端來執行時,SDFE 就特別有用;按照預設,SOAP 擴充的相關資訊不會放入服務描述或為其產生的 Proxy 類別。加密 (Encryption) SOAP 擴充功能是必須同時在用戶端和伺服器上執行的 SOAP 擴充功能範例。如果加密 SOAP 擴充功能在伺服器上執行以加密 SOAP 回應,那麼用戶端便必須執行可解密訊息的 SOAP 擴充功能。SDFE 可以將項目加入至服務描述,通知用戶端必須執行 SOAP 擴充功能,然後 SDFE 可以擴充 Proxy 類別產生處理序,將自訂屬性加入至 Proxy 類別,讓類別執行 SOAP 擴充功能。

下列是建置 SDFE 的基本步驟:

  1. 定義加入至服務描述的 XML。
  2. 撰寫擴充服務描述產生處理序的程式碼。
  3. 撰寫擴充 Proxy 類別產生處理序的程式碼。
  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 命名空間的 usingImports 陳述式加入至檔案。下列程式碼範例建立從 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 在 OperationBinding 擴充點期間,將名為 <action xmlns="https://www.contoso.com/yml"> 的 XML 項目加入至服務描述。在這個範例中,XML 命名空間 https://www.contoso.com/yml 是在 TraceOperationBinding.YMLNamespace 欄位加入至類別後才指定。

    <XmlFormatExtension("action", YMLOperationBinding.YMLNamespace, _
                        GetType(OperationBinding))> _
    Public Class YMLOperationBinding
        Inherits ServiceDescriptionFormatExtension
    [C#]
    [XmlFormatExtension("action", YMLOperationBinding.YMLNamespace,
                        typeof(OperationBinding))]
    public class YMLOperationBinding : ServiceDescriptionFormatExtension
    
  4. 您可以選擇性將 XmlFormatExtensionPrefixAttribute 套用到類別,使 SDFE 使用的 XML 命名空間與 XML 命名空間前置詞產生關聯。

    下列程式碼範例指定 yml XML 命名空間前置詞與服務描述的 <definitions> 項目中的 https://www.contoso.com/yml 命名空間產生關聯。此外,SDFE 加入的項目會使用前置詞而不使用命名空間。因此,步驟 3 中加入至服務描述的 XML 項目,現在會使用命名空間前置詞,所以加入的項目會是 <yml:action> 而不是 <action xmlns="https://www.contoso.com/yml">

    <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。下列程式碼範例將序列化的 Reverse 公用屬性加入至服務描述的 <yml:Reverse>value</yml: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. 覆寫 ReflectMethod 方法,在每個 XML Web Service 方法產生服務描述的時候呼叫。

    下列程式碼範例覆寫 ReflectMethod

    Public Overrides Sub ReflectMethod()
    [C#]
    public override void ReflectMethod()
    
  3. 取得 SoapExtensionReflector 類別的ReflectionContext 屬性值,以取得 ProtocolReflector 的執行個體。

    ProtocolReflector 的執行個體提供目前 XML Web Service 方法的 WSDL 產生處理序的詳細資料。下列程式碼範例會取得 ReflectionContext 屬性值。

    Dim reflector As ProtocolReflector = ReflectionContext
    [C#]
    ProtocolReflector reflector = ReflectionContext;
    
  4. 加入填入 SDFE 的程式碼。

    下列程式碼範例在 YMLAttribute 套用到 XML Web Service 方法時,將 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);
    

若要擴充 Proxy 類別產生處理序

  1. 建立從 SoapExtensionImporter 衍生的類別。

    Public Class YMLImporter
        Inherits SoapExtensionImporter
    [C#]
    public class YMLImporter : SoapExtensionImporter
    
  2. 覆寫 ImportMethod 方法。

    針對在服務描述中定義的每個作業產生 Proxy 類別時,會呼叫ImportMethod。對於使用 ASP.NET 建立的 XML Web Service,每個 XML Web Service 方法對應到服務描述中每個支援的通訊協定的作業。

    Public Overrides Sub ImportMethod(ByVal metadata As _
                                      CodeAttributeDeclarationCollection)
    [C#]
    public override void ImportMethod(CodeAttributeDeclarationCollection
                                      metadata)   
    
  3. 取得 SoapExtensionImporterImportContext 屬性值,以取得 SoapProtocolImporter 的執行個體。

    SoapProtocolImporter 的執行個體提供與 XML Web Service 方法進行通訊之目前方法的程式碼產生處理序的詳細資料。下列程式碼範例會取得 ImportContext 屬性值。

    Dim importer As SoapProtocolImporter = ImportContext
    [C#]
    SoapProtocolImporter importer = ImportContext;  
    
  4. 將要套用或修改屬性的程式碼加入至與 XML Web Service 進行通訊之 Proxy 類別中的方法。

    ImportMethod 傳入 CodeAttributeDeclarationCollection 型別的其中一個引數,表示套用至與 XML Web Service 方法進行通訊之方法的屬性集合。下列程式碼範例將 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 Service 方法來執行

  1. 將包含 SDFE 的組件安裝在可存取的資料夾中。

    除非多個 Web 應用程式需要 SDFE,否則請將 SDFE 安裝在裝載 XML Web Service 的 Web 應用程式的 \Bin 資料夾中。

  2. 使用指定名稱和包含 SDFE 組件的 <add> 項目,將 <serviceDescriptionFormatExtensionTypes> 項目加入至 Web 應用程式的 Web.config 檔案。

    下列程式碼範例設定 Sample.YMLOperationBinding SDFE 配合受到 Web.config 檔案影響的所有 XML Web Service 來執行。完整的 <add> 項目應該在同一行。

    <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 Service 來執行。完整的 <add> 項目應該在同一行。

    <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 Service 用戶端來執行

  1. 將包含 SDFE 的組件安裝在全域組件快取中。

    若要進行安裝,組件必須具有強式名稱 (Strong Name)。如需建立強式名稱組件的詳細資訊,請參閱建立和使用強式名稱的組件。如需安裝組件的詳細資訊,請參閱將組件安裝到全域組件快取

  2. 用指定名稱的 <add> 項目和包含 Machine.config 檔之 SDFE 的組件,加入 <serviceDescriptionFormatExtensionTypes> 項目。

    下列程式碼範例設定在電腦上為 XML Web Service 產生 Proxy 類別時,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. 使用指定名稱和擴充 Proxy 類別產生處理序之類別組件的 <add> 項目,將 <soapExtensionImporterTypes> 項目加入至 Machine.config 檔案。

    下列程式碼範例設定在電腦上為 XML Web Service 產生 Proxy 類別時,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>
    

    **注意   **Proxy 類別所產生的方法會用於與 XML Web Service 進行通訊的用戶端應用程式,所以如果 SDFE 所加入的屬性位於用戶端應用程式所不知道的組件內,就會產生編譯器錯誤。若要解決編譯器錯誤,將參考加入至包含屬性的組件中 (如果使用 Visual Studio .NET),或將組件加入至編譯器命令列 (如果使用命令列編譯)。

完整的 SDFE 程式碼範例

下列程式碼範例中的 SDFE 會擴充服務描述和 Proxy 類別的產生處理序,以包含 YML SOAP 擴充功能詳細資料。

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