Compartir a través de


Personalizar la generación de descripciones de servicio y clases de proxy

La generación de descripciones de servicio y clases de proxy de un servicio Web XML creado mediante ASP.NET puede incluir la creación e instalación de una extensión de formato de descripción de servicio (SDFE). Específicamente, una SDFE puede agregar elementos XML a la descripción de servicio (el documento WSDL de un servicio Web XML) y atributos personalizados a un método que se comunica con un servicio Web XML.

Las SDFE son especialmente útiles cuando se debe ejecutar una extensión SOAP con un servicio Web XML y sus clientes; de forma predeterminada, no se coloca ninguna información acerca de las extensiones SOAP ni en la descripción de servicio ni en las clases de proxy que se generen para ella. Un ejemplo de una extensión SOAP que debe ejecutarse en el cliente y en el servidor es una extensión SOAP de cifrado. Si una extensión SOAP de cifrado se ejecuta en el servidor para cifrar la respuesta SOAP, en el cliente debe existir la extensión SOAP que descifra el mensaje. Una SDFE puede agregar elementos a la descripción de servicio para informar a los clientes que se debe ejecutar una extensión SOAP; así mismo, puede extender el proceso de generación de clases de proxy para agregar un atributo personalizado a la clase de proxy con el fin de que ejecute la extensión SOAP.

A continuación se muestran los pasos básicos para crear una SDFE:

  1. Defina el elemento XML que se va a agregar a la descripción de servicio.
  2. Escriba el código para extender el proceso de generación de descripciones de servicio.
  3. Escriba el código para extender el proceso de generación de clases de proxy.
  4. Configure la SDFE para que se ejecute en el cliente y en el servidor.

En los procedimientos siguientes se explica e ilustra cada paso.

Para definir el elemento XML que se va a agregar a la descripción de servicio

  1. Seleccione el elemento XML que desee agregar a la descripción de servicio.

    El siguiente ejemplo de código contiene la parte de una descripción de servicio a la que la SDFE de ejemplo agrega elementos XML. Específicamente, la SDFE de ejemplo agrega un prefijo del espacio de nombres XML yml al elemento <definitions> y los elementos contenidos en el elemento <yml:action> a los elementos <operation> para enlaces SOAP.

    <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. Cree una clase que se derive de ServiceDescriptionFormatExtension.

    Si utiliza Visual Studio .NET, agregue una referencia al ensamblado System.Web.Services. Agregue también una instrucción using o Imports al espacio de nombres System.Web.Services.Description en el archivo. En el siguiente ejemplo de código se crea la clase TraceOperationBinding, que se deriva de ServiceDescriptionFormatExtension.

    Public Class YMLOperationBinding
        Inherits ServiceDescriptionFormatExtension
    [C#]
    public class YMLOperationBinding : ServiceDescriptionFormatExtension
    
  3. Aplique un atributo XmlFormatExtensionAttribute a la clase.

    Este atributo especifica la fase del proceso de generación de descripciones de servicio, que se conoce como punto de extensión, en que se ejecuta la SDFE. En la tabla siguiente se enumeran los puntos de extensión definidos y los elementos XML de descripción de servicio generados en cada punto.

    Punto de extensión Descripción
    ServiceDescription Corresponde al elemento raíz <definitions> de un documento WSDL.
    Tipos Corresponde al elemento <types> contenido en el elemento raíz <definitions>.
    Binding Corresponde al elemento <binding> contenido en el elemento raíz <definitions>.
    OperationBinding Corresponde al elemento <operation> contenido en el elemento <binding>.
    InputBinding Corresponde al elemento <input> contenido en el elemento <operation>.
    OutputBinding Corresponde al elemento <output> contenido en el elemento <operation>.
    FaultBinding Corresponde al elemento <fault> contenido en el elemento <operation>.
    Port Corresponde al elemento <port> contenido en el elemento <service>.
    Operation Corresponde al elemento <operation> contenido en el elemento <portType>.

    Cuando se aplica un atributo XmlFormatExtensionAttribute a la clase, también se especifica el elemento y el espacio de nombres XML que van a contener los elementos XML que se agregan a la descripción de servicio.

    En el siguiente ejemplo de código se especifica que la SDFE YMLOperationBinding agrega un elemento XML denominado <action xmlns="https://www.contoso.com/yml"> a la descripción de servicio en el punto de extensión OperationBinding. En este ejemplo, el espacio de nombres XML https://www.contoso.com/yml se especifica después de agregar el campo TraceOperationBinding.YMLNamespace a la clase.

    <XmlFormatExtension("action", YMLOperationBinding.YMLNamespace, _
                        GetType(OperationBinding))> _
    Public Class YMLOperationBinding
        Inherits ServiceDescriptionFormatExtension 
    [C#]
    [XmlFormatExtension("action", YMLOperationBinding.YMLNamespace,
                        typeof(OperationBinding))]
    public class YMLOperationBinding : ServiceDescriptionFormatExtension
    
  4. Opcionalmente, aplique un atributo XmlFormatExtensionPrefixAttribute a la clase para asociar el prefijo del espacio de nombres XML con el espacio de nombres XML utilizado por la SDFE.

    En el siguiente ejemplo de código se especifica que el prefijo del espacio de nombres XML yml se asocia con el espacio de nombres https://www.contoso.com/yml del elemento <definitions> de la descripción de servicio. Además, el prefijo se utiliza en los elementos agregados por la SDFE, en vez de en los elementos agregados por el espacio de nombres. Por tanto, el elemento XML agregado a la descripción de servicio en el paso 3 utiliza ahora el prefijo del espacio de nombres y, de este modo, el elemento agregado es <yml:action> en vez de <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. Agregue campos o propiedades públicos a la clase que representa el elemento XML que se va a agregar a la descripción de servicio. En el siguiente ejemplo de código se agrega una propiedad pública Reverse que se serializa en un elemento <yml:Reverse>value</yml:Reverse> de la descripción de servicio.

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

Para extender el proceso de generación de descripciones de servicio.

  1. Cree una clase que se derive de SoapExtensionReflector.

    En el siguiente ejemplo de código se crea la clase TraceReflector, que se deriva de SoapExtensionReflector.

    Public Class YMLReflector
        Inherits SoapExtensionReflector
    [C#]
    public class YMLReflector : SoapExtensionReflector
    
  2. Reemplace el método ReflectMethod, al que se llama durante la generación de descripciones de servicio para cada método de servicio Web XML.

    En el siguiente ejemplo de código se reemplaza el método ReflectMethod.

    Public Overrides Sub ReflectMethod()
    [C#]
    public override void ReflectMethod()
    
  3. Obtenga el valor de la propiedad ReflectionContext de la clase SoapExtensionReflector para crear una instancia de ProtocolReflector.

    La instancia de ProtocolReflector proporciona detalles acerca del proceso de generación WSDL para el método de servicio Web XML actual. En el siguiente ejemplo de código se obtiene el valor de la propiedad ReflectionContext.

    Dim reflector As ProtocolReflector = ReflectionContext
    [C#]
    ProtocolReflector reflector = ReflectionContext;
    
  4. Agregue el código para rellenar la SDFE.

    En el siguiente ejemplo de código se agrega el elemento XML definido por la SDFE para la descripción de servicio si el atributo YMLAttribute se aplica a un método de servicio Web 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. Agregue la SDFE a la colección Extensions de la propiedad que representa el punto de extensión.

    En el siguiente ejemplo de código se agrega la SDFE TraceOperationBinding al punto de extensión OperationBinding.

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

Para extender el proceso de generación de clases de proxy

  1. Cree una clase que se derive de SoapExtensionImporter.

    Public Class YMLImporter
        Inherits SoapExtensionImporter 
    [C#]
    public class YMLImporter : SoapExtensionImporter
    
  2. Reemplace el método ImportMethod.

    Durante la generación de clases de proxy se llama al método ImportMethod cada vez que se define una operación en una descripción de servicio. En los servicios Web XML creados mediante ASP.NET, cada método de servicio Web XML se asigna a una operación en cada protocolo que se admita en la descripción de servicio.

    Public Overrides Sub ImportMethod(ByVal metadata As _
                                      CodeAttributeDeclarationCollection)
    [C#]
    public override void ImportMethod(CodeAttributeDeclarationCollection
                                      metadata)   
    
  3. Obtenga el valor de la propiedad ImportContext de SoapExtensionImporter para crear una instancia de SoapProtocolImporter.

    La instancia de SoapProtocolImporter proporciona detalles acerca del proceso de generación de código para el método actual que se comunica con un método de servicio Web XML. En el siguiente ejemplo de código siguiente se obtiene el valor de la propiedad ImportContext.

    Dim importer As SoapProtocolImporter = ImportContext
    [C#]
    SoapProtocolImporter importer = ImportContext;  
    
  4. Agregue código para aplicar o modificar los atributos a un método en la clase de proxy que se comunica con un servicio Web XML.

    El método ImportMethod pasa un argumento de tipo CodeAttributeDeclarationCollection, que representa la colección de atributos aplicados al método que se comunica con el método de servicio Web XML. En el siguiente ejemplo de código se agrega un atributo YMLAttribute a la colección, que hace que la extensión SOAP YML se ejecute con el método si la descripción de servicio contiene el elemento XML correcto.

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

Para configurar la SDFE para que se ejecute con un servicio Web XML

  1. Instale el ensamblado que contiene la SDFE en una carpeta a la que tenga acceso.

    Salvo que la SDFE sea necesaria en varias aplicaciones Web, instálela en la carpeta \Bin de la aplicación Web que alberga el servicio Web XML.

  2. Agregue un elemento <serviceDescriptionFormatExtensionTypes> con un elemento <add> y especifique el nombre y el ensamblado que contiene la SDFE en el archivo Web.config de la aplicación.

    En el siguiente ejemplo de código se configura la SDFE Sample.YMLOperationBinding para que se ejecute con todos los servicios Web XML a los que afecta el archivo Web.config. El elemento <add> completo debe estar en una sola línea.

    <system.web>
       <webServices>
          <serviceDescriptionFormatExtensionTypes>         <add type="Sample.YMLOperationBinding,Yml,              Version=1.0.0.0,Culture=neutral,              PublicKeyToken=6e55c64c6b897b30"/>      </serviceDescriptionFormatExtensionTypes>
       </webServices>
    </system.web>
    
  3. Agregue un elemento <soapExtensionReflectorTypes> con un elemento <add> y especifique el nombre y el ensamblado de la clase que extiende el proceso de generación de descripciones de servicio en el archivo Web.config de la aplicación Web.

    En el siguiente ejemplo de código se configura la SDFE Sample.YMLReflector para que se ejecute con todos los servicios Web XML a los que afecta el archivo Web.config. El elemento <add> completo debe estar en una sola línea.

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

Para configurar la SDFE para que se ejecute con un cliente de servicios Web XML

  1. Instale el ensamblado que contiene la SDFE en la caché de ensamblados global.

    Para instalar el ensamblado, éste debe tener un nombre seguro. Para obtener más información sobre cómo crear un ensamblado con nombre seguro, vea Crear y utilizar ensamblados con nombre seguro. Para obtener más información sobre cómo instalar un ensamblado, vea Instalar un ensamblado en la caché de ensamblados global.

  2. Agregue un elemento <serviceDescriptionFormatExtensionTypes> con un elemento <add> y especifique el nombre y el ensamblado que contiene la SDFE en el archivo Machine.config.

    En el siguiente ejemplo de código se configura la SDFE Sample.YMLOperationBinding para que se ejecute siempre que se generen clases de proxy para servicios Web XML en el equipo.

    <system.web>
       <webServices>
          <serviceDescriptionFormatExtensionTypes>         <add type="Sample.YMLOperationBinding,Yml,              Version=1.0.0.0,Culture=neutral,              PublicKeyToken=6e55c64c6b897b30"/>      </serviceDescriptionFormatExtensionTypes>
       </webServices>
    </system.web>
    
  3. Agregue un elemento <soapExtensionImporterTypes> con un elemento <add> y especifique el nombre y el ensamblado de la clase que extiende el proceso de generación de descripciones de servicio en el archivo Machine.config.

    En el siguiente ejemplo de código se configura la extensión Sample.YMLImporter para que se ejecute siempre que se generen clases de proxy para servicios Web XML en el equipo.

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

    **Nota   **Como el método generado en la clase de proxy se utiliza en una aplicación cliente que se comunica con el servicio Web XML, si una SDFE agrega un atributo que reside en un ensamblado que la aplicación cliente no conoce, se producirá un error en el compilador. Para solucionar el error del compilador, agregue una referencia al ensamblado que contiene el atributo si utiliza Visual Studio .NET, o a la línea de comandos del compilador si utiliza este tipo de compilación.

Ejemplo de código de extensión SDFE completo

El siguiente ejemplo de código contiene una SDFE que extiende los procesos de generación de descripciones de servicio y de clases de proxy con el fin de incluir detalles acerca de una extensión SOAP YML.

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

Vea también

Alterar el mensaje SOAP mediante extensiones SOAP | XmlFormatExtensionAttribute | XmlFormatExtensionPrefixAttribute | XmlFormatExtensionPointAttribute