Freigeben über


Anpassen der Generierung von Dienstbeschreibungen und Proxyklassen

Die Generierung der Dienstbeschreibung und der Proxyklassen eines mit ASP.NET erstellten XML-Webdienstes kann durch das Erstellen und Installieren einer Dienstbeschreibungs-Formaterweiterung (SDFE, Service Description Format Extension) erweitert werden. Insbesondere können mit der SDFE der Dienstbeschreibung, d. h. dem WSDL-Dokument für einen XML-Webdienst, XML-Elemente hinzugefügt und einer Methode, die mit einem XML-Webdienst kommuniziert, benutzerdefinierte Attribute hinzugefügt werden.

SDFEs bieten sich besonders an, wenn eine SOAP-Erweiterung sowohl mit einem XML-Webdienst als auch mit seinen Clients ausgeführt werden soll. In der Standardeinstellung werden keine Informationen über SOAP-Erweiterungen in der Dienstbeschreibung oder in den hierfür generierten Proxyklassen platziert. Ein Beispiel für eine SOAP-Erweiterung, die sowohl auf dem Client als auch auf dem Server ausgeführt werden muss, ist eine Verschlüsselungs-SOAP-Erweiterung. Wenn eine SOAP-Verschlüsselungserweiterung zum Verschlüsseln der SOAP-Antwort auf dem Server ausgeführt wird, muss der Client die SOAP-Erweiterung zum Entschlüsseln der Meldung ausführen. Eine SDFE kann der Dienstbeschreibung Elemente hinzufügen, um Clients darüber zu benachrichtigen, dass eine SOAP-Erweiterung ausgeführt werden muss. Außerdem kann die SDFE den Generierungsprozess der Proxyklasse erweitern, um der Proxyklasse ein benutzerdefiniertes Attribut hinzuzufügen, so dass die SOAP-Erweiterung von der Klasse ausgeführt wird.

Im Folgenden sind die grundlegenden Schritte zum Erstellen einer SDFE aufgeführt:

  1. Definieren Sie den der Dienstbeschreibung hinzuzufügenden XML-Code.
  2. Schreiben Sie Code zum Erweitern des Generierungsprozesses der Dienstbeschreibung.
  3. Schreiben Sie Code zum Erweitern des Generierungsprozesses der Proxyklasse.
  4. Konfigurieren Sie die SDFE für die Ausführung auf Client und Server.

Im Folgenden wird jeder Schritt erklärt und veranschaulicht.

So definieren Sie den der Dienstbeschreibung hinzuzufügenden XML-Code

  1. Bestimmen Sie den der Dienstbeschreibung hinzuzufügenden XML-Code.

    Im folgenden Codebeispiel wird der Teil einer Dienstbeschreibung dargestellt, dem XML-Elemente durch die Beispiel-SDFE hinzugefügt werden. Dabei werden durch die Beispiel-SDFE dem <definitions>-Element das XML-Namespacepräfix yml und den <operation>-Elementen für SOAP-Bindungen die im <yml:action>-Element enthaltenen Elemente hinzugefügt.

    <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. Erstellen Sie eine von ServiceDescriptionFormatExtension abgeleitete Klasse.

    Fügen Sie bei Verwendung von Visual Studio .NET einen Verweis auf die System.Web.Services-Assembly hinzu. Fügen Sie der Datei außerdem eine using-Anweisung oder eine Imports-Anweisung für den System.Web.Services.Description-Namespace hinzu. Im folgenden Codebeispiel wird die von ServiceDescriptionFormatExtension abgeleitete TraceOperationBinding-Klasse erstellt.

    Public Class YMLOperationBinding
        Inherits ServiceDescriptionFormatExtension
    [C#]
    public class YMLOperationBinding : ServiceDescriptionFormatExtension
    
  3. Wenden Sie ein XmlFormatExtensionAttribute auf die Klasse an.

    Dieses Attribut gibt die Stufe des Generierungsprozesses für die Dienstbeschreibung an, die als der Erweiterungspunkt bezeichnet ist, an dem die SDFE ausgeführt wird. In der folgenden Tabelle werden die definierten Erweiterungspunkte und die während jedes Punktes generierten XML-Elemente der Dienstbeschreibung aufgelistet.

    Erweiterungspunkt Beschreibung
    ServiceDescription Entspricht dem <definitions>-Stammelement eines WSDL-Dokuments.
    Types Entspricht dem vom <definitions>-Stammelement eingeschlossenen <types>-Element.
    Binding Entspricht dem vom <definitions>-Stammelement eingeschlossenen <binding>-Element.
    OperationBinding Entspricht dem vom <binding>-Element eingeschlossenen <operation>-Element.
    InputBinding Entspricht dem vom <operation>-Element eingeschlossenen <input>-Element.
    OutputBinding Entspricht dem vom <operation>-Element eingeschlossenen <output>-Element.
    FaultBinding Entspricht dem vom <operation>-Element eingeschlossenen <fault>-Element.
    Port Entspricht dem vom <service>-Element eingeschlossenen <port>-Element.
    Operation Entspricht dem vom <portType>-Element eingeschlossenen <operation>-Element.

    Wenn ein XmlFormatExtensionAttribute auf die Klasse angewendet wird, geben Sie außerdem das XML-Element und den XML-Namespace an, die die XML-Elemente enthalten sollen, die der Dienstbeschreibung hinzuzufügen sind.

    Im folgenden Codebeispiel wird angegeben, dass die YMLOperationBinding-SDFE der Dienstbeschreibung während des OperationBinding-Erweiterungspunkts das XML-Element <action xmlns="https://www.contoso.com/yml"> hinzufügt. In diesem Beispiel wird der XML-Namespace https://www.contoso.com/yml angegeben, wenn das TraceOperationBinding.YMLNamespace-Feld später der Klasse hinzugefügt wird.

    <XmlFormatExtension("action", YMLOperationBinding.YMLNamespace, _
                        GetType(OperationBinding))> _
    Public Class YMLOperationBinding
        Inherits ServiceDescriptionFormatExtension 
    [C#]
    [XmlFormatExtension("action", YMLOperationBinding.YMLNamespace,
                        typeof(OperationBinding))]
    public class YMLOperationBinding : ServiceDescriptionFormatExtension
    
  4. Wahlweise können Sie ein XmlFormatExtensionPrefixAttribute auf die Klasse anwenden, um das XML-Namespacepräfix dem von der SDFE verwendeten Namespace zuzuordnen.

    Im folgenden Codebeispiel wird angegeben, dass das XML-Namespacepräfix yml dem https://www.contoso.com/yml-Namespace im <definitions>-Element der Dienstbeschreibung zugeordnet wird. Außerdem wird bei Elementen, die von der SDFE hinzugefügt werden, anstelle des Namespace das Präfix verwendet. Das der Dienstbeschreibung in Schritt 3 hinzugefügte XML-Element verwendet nun das Namespacepräfix, und das hinzugefügte Element lautet daher <yml:action> und nicht <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. Fügen Sie öffentliche Eigenschaften und/oder Felder der Klasse hinzu, die den XML-Code darstellt, der der Dienstbeschreibung hinzuzufügen ist. Im folgenden Codebeispiel wird eine öffentliche Reverse-Eigenschaft hinzugefügt, die in ein <yml:Reverse>value</yml:Reverse>-Element in der Dienstbeschreibung serialisiert wird.

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

So erweitern Sie den Generierungsprozess der Dienstbeschreibung

  1. Erstellen Sie eine von SoapExtensionReflector abgeleitete Klasse.

    Im folgenden Codebeispiel wird die TraceReflector-Klasse erstellt, die von SoapExtensionReflector abgeleitet ist.

    Public Class YMLReflector
        Inherits SoapExtensionReflector
    [C#]
    public class YMLReflector : SoapExtensionReflector
    
  2. Überschreiben Sie die ReflectMethod-Methode, die während der Generierung der Dienstbeschreibung für alle XML-Webdienstmethoden aufgerufen wird.

    Im folgenden Codebeispiel wird die ReflectMethod überschrieben.

    Public Overrides Sub ReflectMethod()
    [C#]
    public override void ReflectMethod()
    
  3. Rufen sie den Wert der ReflectionContext-Eigenschaft der SoapExtensionReflector-Klasse ab, um eine Instanz von ProtocolReflector abzurufen.

    Die Instanz von ProtocolReflector stellt Details über den WSDL-Generierungsprozess für die aktuelle XML-Webdienstmethode bereit. Im folgenden Codebeispiel wird der Wert der ReflectionContext-Eigenschaft abgerufen.

    Dim reflector As ProtocolReflector = ReflectionContext
    [C#]
    ProtocolReflector reflector = ReflectionContext;
    
  4. Fügen Sie Code hinzu, mit dem die SDFE aufgefüllt wird.

    Im folgenden Codebeispiel wird der Dienstbeschreibung der von der SDFE definierte XML-Code hinzugefügt, wenn das YMLAttribute auf eine XML-Webdienstmethode angewendet wird.

    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. Fügen Sie die SDFE der Extensions-Auflistung der Eigenschaft hinzu, die den von der SDFE erweiterten Erweiterungspunkt darstellt.

    Im folgenden Codebeispiel wird die TraceOperationBinding-SDFE dem OperationBinding-Erweiterungspunkt hinzugefügt.

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

So erweitern Sie den Generierungsprozesses der Proxyklasse

  1. Erstellen Sie eine von SoapExtensionImporter abgeleitete Klasse.

    Public Class YMLImporter
        Inherits SoapExtensionImporter 
    [C#]
    public class YMLImporter : SoapExtensionImporter
    
  2. Überschreiben Sie die ImportMethod-Methode.

    ImportMethod wird während der Generierung der Proxyklasse für alle in einer Dienstbeschreibung definierten Operationen aufgerufen. Bei mit ASP.NET erstellten XML-Webdiensten wird für die einzelnen unterstützten Protokolle in der Dienstbeschreibung jede XML-Webdienstmethode einer Operation zugeordnet.

    Public Overrides Sub ImportMethod(ByVal metadata As _
                                      CodeAttributeDeclarationCollection)
    [C#]
    public override void ImportMethod(CodeAttributeDeclarationCollection
                                      metadata)   
    
  3. Rufen sie den Wert der ImportContext-Eigenschaft von SoapExtensionImporter ab, um eine Instanz von SoapProtocolImporter abzurufen.

    Die Instanz von SoapProtocolImporter stellt Details über den Prozess der Codegenerierung für die aktuelle Methode bereit, die mit einer XML-Webdienstmethode kommuniziert. Im folgenden Codebeispiel wird der Wert der ImportContext-Eigenschaft abgerufen.

    Dim importer As SoapProtocolImporter = ImportContext
    [C#]
    SoapProtocolImporter importer = ImportContext;  
    
  4. Fügen Sie Code hinzu, um Attribute für eine Methode in der Proxyklasse, die mit einem XML-Webdienst kommuniziert, zu ändern oder hinzuzufügen.

    ImportMethod übergibt ein Argument vom Typ CodeAttributeDeclarationCollection, das die Auflistung von Attributen darstellt, die auf die mit der XML-Webdienstmethode kommunizierende Methode angewendet werden. Im folgenden Codebeispiel wird der Auflistung ein YMLAttribute hinzugefügt. Dadurch wird die SOAP-Erweiterung YML mit der Methode ausgeführt, wenn die Dienstbeschreibung den entsprechenden XML-Code enthält.

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

So konfigurieren Sie die SDFE für die Ausführung mit einem XML-Webdienst

  1. Installieren Sie die Assembly mit der SDFE in einem Order, der zugänglich ist.

    Wenn die SDFE nicht für mehrere Webanwendungen benötigt wird, installieren Sie die SDFE im Ordner \Bin der Webanwendung, die den Host für den XML-Webdienst darstellt.

  2. Fügen Sie der Web.config-Datei der Webanwendung ein <serviceDescriptionFormatExtensionTypes>-Element mit einem <add>-Element hinzu, das den Namen und die Assembly angibt, die die SDFE enthält.

    Im folgenden Codebeispiel wird die Sample.YMLOperationBinding-SDFE für die Ausführung mit allen XML-Webdiensten konfiguriert, auf die sich die Datei Web.config auswirkt. Das gesamte <add>-Element sollte sich in einer Zeile befinden.

    <system.web>
       <webServices>
          <serviceDescriptionFormatExtensionTypes>         <add type="Sample.YMLOperationBinding,Yml,              Version=1.0.0.0,Culture=neutral,              PublicKeyToken=6e55c64c6b897b30"/>      </serviceDescriptionFormatExtensionTypes>
       </webServices>
    </system.web>
    
  3. Fügen Sie der Web.config-Datei der Webanwendung ein <soapExtensionReflectorTypes>-Element mit einem <add>-Element hinzu, das den Namen und die Assembly der Klasse angibt, die den Generierungsprozess der Dienstbeschreibung erweitert.

    Im folgenden Codebeispiel wird Sample.YMLReflector für die Ausführung mit allen XML-Webdiensten konfiguriert, auf die sich die Datei Web.config auswirkt. Das gesamte <add>-Element sollte sich in einer Zeile befinden.

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

So konfigurieren Sie die SDFE für die Ausführung mit einem XML-Webdienstclient

  1. Installieren Sie die Assembly mit der SDFE im globalen Assemblycache.

    Die Assembly muss über einen starken Namen verfügen, um installiert werden zu können. Weitere Informationen zum Erstellen von Assemblies mit starken Namen finden Sie unter Erstellen und Verwenden von Assemblies mit starkem Namen. Weitere Informationen zum Installieren einer Assembly finden Sie unter Installieren einer Assembly in den globalen Assemblycache.

  2. Fügen Sie der Datei Machine.config ein <serviceDescriptionFormatExtensionTypes>-Element mit einem <add>-Element hinzu, das den Namen und Assembly angibt, die die SDFE enthält.

    Im folgenden Codebeispiel wird die Sample.YMLOperationBinding-SDFE so konfiguriert, dass sie immer dann ausgeführt wird, wenn Proxyklassen für XML-Webdienste auf dem Computer generiert werden.

    <system.web>
       <webServices>
          <serviceDescriptionFormatExtensionTypes>         <add type="Sample.YMLOperationBinding,Yml,              Version=1.0.0.0,Culture=neutral,              PublicKeyToken=6e55c64c6b897b30"/>      </serviceDescriptionFormatExtensionTypes>
       </webServices>
    </system.web>
    
  3. Fügen Sie der Datei Machine.config ein <soapExtensionImporterTypes>-Element mit einem <add>-Element hinzu, das den Namen und die Assembly der Klasse angibt, die den Generierungsprozess der Proxyklasse erweitert.

    Im folgenden Codebeispiel wird Sample.YMLImporter so konfiguriert, dass dieser immer dann ausgeführt wird, wenn Proxyklassen für XML-Webdienste auf dem Computer generiert werden.

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

    **Hinweis   **Die in der Proxyklasse generierte Methode wird von einer Clientanwendung verwendet, die mit dem XML-Webdienst kommuniziert. Wenn eine SDFE daher ein Attribut hinzufügt, das in einer der Clientanwendung unbekannten Assembly enthalten ist, wird ein Compilerfehler generiert. Um den Compilerfehler aufzulösen, fügen Sie bei Verwendung von Visual Studio .NET der Assembly, die das Attribut enthält, einen Verweis hinzu. Wahlweise können Sie bei der Kompilierung von der Befehlszeile aus die Assembly der Compilerbefehlszeile hinzufügen.

Vollständiger SDFE-Beispielcode

Das folgende Codebeispiel veranschaulicht eine SDFE, die die Prozesse der Dienstbeschreibung und der Proxygenerierung dahin gehend erweitert, dass diese Einzelheiten zu einer SOAP-YML-Erweiterung enthalten.

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

Siehe auch

Ändern der SOAP-Meldung mit SOAP-Erweiterungen | XmlFormatExtensionAttribute | XmlFormatExtensionPrefixAttribute | XmlFormatExtensionPointAttribute