Partager via


Personnalisation de la génération des descriptions de service et des classes proxy

La génération de description de service et des classes proxy d'un service Web XML créé à l'aide de ASP.NET peut être étendue par la création et l'installation d'une extension de format de description de service. En particulier, une extension de format de description de service peut ajouter des éléments XML à la description de service — le document WSDL d'un service Web XML — et des attributs personnalisés à une méthode communiquant avec un service Web XML.

Les extensions de format de description de service sont particulièrement utiles lorsqu'une extension SOAP doit être exécutée avec un service Web XML et ses clients ; par défaut, aucune information relative aux extensions SOAP n'est placée dans la description du service ni dans les classes proxy générées pour lui. Par exemple, une extension SOAP de cryptage doit être exécutée à la fois sur le client et sur le serveur. Si une extension SOAP de cryptage est exécutée sur le serveur pour crypter la réponse SOAP, le client doit avoir l'extension SOAP active pour décrypter le message. Une extension de format de description de service peut ajouter des éléments à la description de service pour informer les clients qu'une extension SOAP doit être active et étendre le processus de génération de classe proxy pour ajouter un attribut personnalisé à la classe proxy, déclenchant l'exécution par celle-ci de l'extension SOAP.

La procédure de base suivante décrit comment construire une extension de format de description de service :

  1. Définissez le XML à ajouter à la description de service.
  2. Écrivez du code pour étendre le processus de génération de description de service.
  3. Écrivez du code pour étendre le processus de génération de classe proxy.
  4. Configurez l'extension de format de description de service de telle sorte qu'elle s'exécute sur le client et sur le serveur.

Les procédures suivantes expliquent et illustrent chaque étape.

Pour définir le XML à ajouter à la description de service

  1. Choisissez le XML à ajouter à la description de service.

    L'exemple de code suivant correspond à la partie d'une description de service à laquelle l'exemple d'extension de format de description de service ajoute les éléments XML. En particulier, cet exemple ajoute un préfixe d'espace de noms XML yml à l'élément <definitions> et les éléments contenus dans l'élément <yml:action> aux éléments <operation> pour les liaisons 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. Créez une classe dérivée de ServiceDescriptionFormatExtension.

    Lorsque vous utilisez Visual Studio .NET, ajoutez une référence à l'assembly System.Web.Services. Ajoutez également une instruction using ou Imports au fichier pour l'espace de noms System.Web.Services.Description. L'exemple de code suivant crée la classe TraceOperationBinding dérivée de ServiceDescriptionFormatExtension.

    Public Class YMLOperationBinding
        Inherits ServiceDescriptionFormatExtension
    [C#]
    public class YMLOperationBinding : ServiceDescriptionFormatExtension
    
  3. Appliquez XMLFormatExtensionAttribute à la classe.

    Cet attribut spécifie le stade du processus de génération de description de service, également appelé « point d'extension », auquel s'exécute l'extension de format de description de service. Le tableau suivant répertorie les points d'extension définis et les éléments XML de description de service générés durant chacun d'eux.

    Point d'extension Description
    ServiceDescription Correspond à l'élément <definitions> racine d'un document WSDL.
    Types Correspond à l'élément <types> inséré dans l'élément <definitions> racine.
    Binding Correspond à l'élément <binding> inséré dans l'élément <definitions> racine.
    OperationBinding Correspond à l'élément <operation> inséré dans l'élément <binding>.
    InputBinding Correspond à l'élément <input> inséré dans l'élément <operation>.
    OutputBinding Correspond à l'élément <output> inséré dans l'élément <operation>.
    FaultBinding Correspond à l'élément <fault> inséré dans l'élément <operation>.
    Port Correspond à l'élément <port> inséré dans l'élément <service>.
    Operation Correspond à l'élément <operation> inséré dans l'élément <portType>.

    Lorsque vous appliquez XmlFormatExtensionAttribute à la classe, vous spécifiez également l'élément XML et l'espace de noms XML destiné à contenir les éléments XML à ajouter à la description de service.

    L'exemple de code suivant spécifie que l'extension de format de description de service YMLOperationBinding ajoute un élément XML appelé <action xmlns="https://www.contoso.com/yml"> à la description de service durant le point d'extension OperationBinding. Pour cet exemple, l'espace de noms XML https://www.contoso.com/yml est spécifié ultérieurement, lorsque le champ TraceOperationBinding.YMLNamespace est ajouté à la classe.

    <XmlFormatExtension("action", YMLOperationBinding.YMLNamespace, _
                        GetType(OperationBinding))> _
    Public Class YMLOperationBinding
        Inherits ServiceDescriptionFormatExtension 
    [C#]
    [XmlFormatExtension("action", YMLOperationBinding.YMLNamespace,
                        typeof(OperationBinding))]
    public class YMLOperationBinding : ServiceDescriptionFormatExtension
    
  4. Le cas échéant, appliquez XmlFormatExtensionPrefixAttribute à la classe pour associer le préfixe d'espace de noms XML à l'espace de noms XML utilisé par l'extension de format de description de service.

    L'exemple de code suivant spécifie que le préfixe d'espace de noms XML yml est associé à l'espace de noms https://www.contoso.com/yml dans l'élément <definitions> de la description de service. En outre, le préfixe est utilisé dans des éléments ajoutés par l'extension de format de description de service plutôt que par l'espace de noms. Par conséquent, l'élément XML ajouté à la description de service à l'étape 3 utilise désormais le préfixe d'espace de noms ; l'élément ajouté est donc <yml:action> au lieu 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. Ajoutez les propriétés et/ou les champs publics à la classe représentant le XML à ajouter à la description de service. L'exemple de code suivant ajoute une propriété publique Reverse qui est sérialisée dans un élément <yml:Reverse>value</yml:Reverse> dans la description de service.

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

Pour étendre le processus de génération de description de service

  1. Créez une classe dérivée de SoapExtensionReflector.

    L'exemple de code suivant crée la classe TraceReflector dérivée de SoapExtensionReflector.

    Public Class YMLReflector
        Inherits SoapExtensionReflector
    [C#]
    public class YMLReflector : SoapExtensionReflector
    
  2. Substituez la méthode ReflectMethod qui est appelée durant la génération de la description de service pour chaque méthode de service Web XML.

    L'exemple de code suivant substitue ReflectMethod.

    Public Overrides Sub ReflectMethod()
    [C#]
    public override void ReflectMethod()
    
  3. Obtenez la valeur de la propriété ReflectionContext de la classe SoapExtensionReflector pour obtenir une instance de ProtocolReflector.

    L'instance de ProtocolReflector fournit des détails sur le processus de génération WSDL pour la méthode de service Web XML actuelle. L'exemple de code suivant obtient la valeur de la propriété ReflectionContext.

    Dim reflector As ProtocolReflector = ReflectionContext
    [C#]
    ProtocolReflector reflector = ReflectionContext;
    
  4. Ajoutez du code pour remplir l'extension de format de description de service.

    L'exemple de code suivant ajoute le XML défini par l'extension de format de description de service à la description de service si YMLAttribute est appliqué à une méthode de service 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. Ajoutez l'extension de format de description de service à la collection Extensions de la propriété représentant le point d'extension qu'étend l'extension de format de description de service.

    L'exemple de code suivant ajoute l'extension de format de description de service TraceOperationBinding au point d'extension OperationBinding.

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

Pour étendre le processus de génération de classe proxy

  1. Créez une classe dérivant de SoapExtensionImporter.

    Public Class YMLImporter
        Inherits SoapExtensionImporter 
    [C#]
    public class YMLImporter : SoapExtensionImporter
    
  2. Substituez la méthode ImportMethod.

    ImportMethod est appelé durant la génération de classe proxy pour chaque opération définie dans une description de service. Pour les services Web XML créés à l'aide de ASP.NET, chaque méthode de service Web XML correspond à une opération pour chaque protocole pris en charge dans la description de service.

    Public Overrides Sub ImportMethod(ByVal metadata As _
                                      CodeAttributeDeclarationCollection)
    [C#]
    public override void ImportMethod(CodeAttributeDeclarationCollection
                                      metadata)   
    
  3. Obtenez la valeur de la propriété ImportContext de SoapExtensionImporter pour obtenir une instance de SoapProtocolImporter.

    L'instance de SoapProtocolImporter fournit des détails sur le processus de génération du code pour la méthode actuelle communiquant avec une méthode de service Web XML. L'exemple de code suivant obtient la valeur de la propriété ImportContext.

    Dim importer As SoapProtocolImporter = ImportContext
    [C#]
    SoapProtocolImporter importer = ImportContext;  
    
  4. Ajoutez du code pour appliquer ou modifier les attributs à une méthode de la classe proxy qui communique avec un service Web XML.

    ImportMethod passe dans un argument de type CodeAttributeDeclarationCollection qui représente la collection des attributs appliqués à la méthode communiquant avec la méthode de service Web XML. L'exemple de code suivant ajoute YMLAttribute à la collection, en conséquence de quoi l'extension SOAP YML s'exécute avec la méthode lorsque la description de service contient le XML approprié.

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

Pour configurer l'extension de format de description de service pour une exécution avec un service Web XML

  1. Installez l'assembly contenant l'extension de format de description de service dans un dossier accessible.

    Sauf si l'extension de format de description de service est nécessaire à plusieurs applications Web, installez-la dans le dossier \Bin de l'application Web hébergeant le service Web XML.

  2. Ajoutez au fichier Web.config de l'application Web un élément <serviceDescriptionFormatExtensionTypes> avec un élément <add> spécifiant le nom et l'assembly qui contient l'extension de format de description de service.

    L'exemple de code suivant configure l'extension de format de description de service Sample.YMLOperationBinding pour une exécution avec tous les services Web XML affectés par le fichier Web.config. L'élément <add> complet doit figurer sur une ligne.

    <system.web>
       <webServices>
          <serviceDescriptionFormatExtensionTypes>         <add type="Sample.YMLOperationBinding,Yml,              Version=1.0.0.0,Culture=neutral,              PublicKeyToken=6e55c64c6b897b30"/>      </serviceDescriptionFormatExtensionTypes>
       </webServices>
    </system.web>
    
  3. Ajoutez au fichier Web.config de l'application Web un <soapExtensionReflectorTypes> avec un élément <add> spécifiant le nom et l'assembly de la classe qui étend le processus de génération de description de service.

    L'exemple de code suivant configure Sample.YMLReflector pour une exécution avec tous les services Web XML affectés par le fichier Web.config. L'élément <add> complet doit figurer sur une ligne.

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

Pour configurer l'extension de format de description de service pour une exécution avec un client de service Web XML

  1. Installez l'assembly contenant l'extension de format de description de service dans le cache d'assembly global.

    Pour être installé, l'assembly doit avoir un nom fort. Pour plus d'informations sur la création d'un nom fort pour un assembly, consultez Création et utilisation d'assemblys avec nom fort. Pour plus d'informations sur l'installation d'un assembly, consultez Installation d'un assembly dans le cache de l'assembly global.

  2. Ajoutez au fichier Machine.config un élément <serviceDescriptionFormatExtensionTypes> avec un élément <add> spécifiant le nom et l'assembly qui contient l'extension de format de description de service.

    L'exemple de code suivant configure l'extension de format de description de service Sample.YMLOperationBinding pour qu'elle s'exécute chaque fois que des classes proxy sont générées pour des services Web XML sur l'ordinateur.

    <system.web>
       <webServices>
          <serviceDescriptionFormatExtensionTypes>         <add type="Sample.YMLOperationBinding,Yml,              Version=1.0.0.0,Culture=neutral,              PublicKeyToken=6e55c64c6b897b30"/>      </serviceDescriptionFormatExtensionTypes>
       </webServices>
    </system.web>
    
  3. Ajoutez au fichier Machine.config un élément <soapExtensionImporterTypes> avec un élément <add> spécifiant le nom et l'assembly de la classe qui étend le processus de génération de la classe proxy.

    L'exemple de code suivant configure Sample.YMLImporter pour qu'il s'exécute chaque fois que des classes proxy sont générées pour des services Web XML sur l'ordinateur.

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

    **Remarque   **La méthode générée dans la classe proxy est utilisée par une application cliente communiquant avec le service Web XML ; par conséquent, si une extension de format de description de service ajoute un attribut résidant dans un assembly inconnu de l'application cliente, une erreur de compilation est générée. Pour résoudre l'erreur de compilation, ajoutez une référence à l'assembly contenant l'attribut si vous utilisez Visual Studio .NET ou ajoutez l'assembly à la ligne de commande du compilateur si vous utilisez la compilation de ligne de commande.

Exemple de code d'extension de format de description de service complet

L'exemple de code suivant est une extension de format de description de service qui étend les processus de description de service et de génération de proxy pour inclure des détails au sujet d'une extension 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; }
   }
}

Voir aussi

Modification du message SOAP à l'aide des extensions SOAP | XMLFormatExtensionAttribute | XmlFormatExtensionPrefixAttribute | XmlFormatExtensionPointAttribute