Partager via


Publication WSDL personnalisée

Cet exemple montre comment :

Aa717040.note(fr-fr,VS.90).gifRemarque :
La procédure d'installation ainsi que les instructions de génération relatives à cet exemple figurent à la fin de cette rubrique.

Service

Le service dans cet exemple est marqué avec deux attributs personnalisés. Le premier, WsdlDocumentationAttribute, accepte une chaîne dans le constructeur et peut être appliqué pour fournir une interface de contrat ou d'opération avec une chaîne qui décrit son utilisation. Le second, WsdlParamOrReturnDocumentationAttribute, peut être appliqué aux valeurs ou aux paramètres de retour pour décrire ces valeurs dans l'opération. L'exemple suivant illustre un contrat de service, ICalculator, décrit à l'aide de ces attributs.

// Define a service contract.    
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
// Document it.
[WsdlDocumentation("The ICalculator contract performs basic calculation services.")]
public interface ICalculator
{
    [OperationContract]
    [WsdlDocumentation("The Add operation adds two numbers and returns the result.")]
    [return:WsdlParamOrReturnDocumentation("The result of adding the two arguments together.")]
    double Add(
      [WsdlParamOrReturnDocumentation("The first value to add.")]double n1, 
      [WsdlParamOrReturnDocumentation("The second value to add.")]double n2
    );
    
    [OperationContract]
    [WsdlDocumentation("The Subtract operation subtracts the second argument from the first.")]
    [return:WsdlParamOrReturnDocumentation("The result of the second argument subtracted from the first.")]
    double Subtract(
      [WsdlParamOrReturnDocumentation("The value from which the second is subtracted.")]double n1, 
      [WsdlParamOrReturnDocumentation("The value that is subtracted from the first.")]double n2
    );
    
    [OperationContract]
    [WsdlDocumentation("The Multiply operation multiplies two values.")]
    [return:WsdlParamOrReturnDocumentation("The result of multiplying the first and second arguments.")]
    double Multiply(
      [WsdlParamOrReturnDocumentation("The first value to multiply.")]double n1, 
      [WsdlParamOrReturnDocumentation("The second value to multiply.")]double n2
    );

    [OperationContract]
    [WsdlDocumentation("The Divide operation returns the value of the first argument divided by the second argument.")]
    [return:WsdlParamOrReturnDocumentation("The result of dividing the first argument by the second.")]
    double Divide(
      [WsdlParamOrReturnDocumentation("The numerator.")]double n1, 
      [WsdlParamOrReturnDocumentation("The denominator.")]double n2
    );
}
 

L'WsdlDocumentationAttribute implémente IContractBehavior et IOperationBehavior, donc les instances d'attribut sont ajoutées à la ContractDescription correspondante ou à la OperationDescription lorsque le service est ouvert. L'attribut implémente également IWsdlExportExtension. Lorsque ExportContract est appelée, le WsdlExporter utilisé pour exporter les métadonnées et le WsdlContractConversionContext qui contient les objets de description du service sont passés comme des paramètres permettant la modification des métadonnées exportées.

Dans cet exemple, selon que l'objet de contexte d'exportation a une ContractDescription ou une OperationDescription, un commentaire est extrait de l'attribut à l'aide de la propriété de texte et est ajouté à l'élément d'annotation WSDL comme le montre le code suivant.

public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
{
    if (contractDescription != null)
    {
        // Inside this block it is the contract-level comment attribute.
        // This.Text returns the string for the contract attribute.
        // Set the doc element; if this isn't done first, there is no XmlElement in the 
        // DocumentElement property.
        context.WsdlPortType.Documentation = string.Empty;
        // Contract comments.
        XmlDocument owner = context.WsdlPortType.DocumentationElement.OwnerDocument;
        XmlElement summaryElement = owner.CreateElement("summary");
        summaryElement.InnerText = this.Text;
        context.WsdlPortType.DocumentationElement.AppendChild(summaryElement);
    }
    else
    {
        Operation operation = context.GetOperation(operationDescription);
        if (operation != null)
        {
            // We are dealing strictly with the operation here.
            // This.Text returns the string for the operation-level attributes.
            // Set the doc element; if this isn't done first, there is no XmlElement in the 
            // DocumentElement property.
            operation.Documentation = String.Empty;

            // Operation C# triple comments.
            XmlDocument owner = operation.DocumentationElement.OwnerDocument;
            XmlElement newSummaryElement = owner.CreateElement("summary");
            newSummaryElement.InnerText = this.Text;
            operation.DocumentationElement.AppendChild(newSummaryElement);

Si une opération est en cours d'exportation, l'exemple utilise la réflexion pour obtenir toutes valeurs WsdlParamOrReturnDocumentationAttribute pour les paramètres et les valeurs de retour et les ajoute aux éléments d'annotation WSDL pour cette opération comme suit.

// Get returns information
ParameterInfo returnValue = operationDescription.SyncMethod.ReturnParameter;
object[] returnAttrs = returnValue.GetCustomAttributes(typeof(WsdlParamOrReturnDocumentationAttribute), false);
if (returnAttrs.Length != 0)
{
    // <returns>text.</returns>
    XmlElement returnsElement = owner.CreateElement("returns");
    returnsElement.InnerText = ((WsdlParamOrReturnDocumentationAttribute)returnAttrs[0]).ParamComment;
    operation.DocumentationElement.AppendChild(returnsElement);
}

// Get parameter information.
ParameterInfo[] args = operationDescription.SyncMethod.GetParameters();
for (int i = 0; i < args.Length; i++)
{
    object[] docAttrs = args[i].GetCustomAttributes(typeof(WsdlParamOrReturnDocumentationAttribute), false);
    if (docAttrs.Length == 1)
    {
        // <param name="Int1">Text.</param>
        XmlElement newParamElement = owner.CreateElement("param");
        XmlAttribute paramName = owner.CreateAttribute("name");
        paramName.Value = args[i].Name;
        newParamElement.InnerText = ((WsdlParamOrReturnDocumentationAttribute)docAttrs[0]).ParamComment;
        newParamElement.Attributes.Append(paramName);
        operation.DocumentationElement.AppendChild(newParamElement);
    }
}

L'exemple publie ensuite les métadonnées de la manière standard, à l'aide du fichier de configuration suivant.

<services>
  <service 
      name="Microsoft.ServiceModel.Samples.CalculatorService"
      behaviorConfiguration="CalculatorServiceBehavior">
    <!-- ICalculator is exposed at the base address provided by host: https://localhost/servicemodelsamples/service.svc  -->
    <endpoint address=""
              binding="wsHttpBinding"
              contract="Microsoft.ServiceModel.Samples.ICalculator" />
    <!-- the mex endpoint is exposed at https://localhost/servicemodelsamples/service.svc/mex -->
    <endpoint address="mex"
              binding="mexHttpBinding"
              contract="IMetadataExchange" />
  </service>
</services>

<!--For debugging purposes set the includeExceptionDetailInFaults attribute to true-->
<behaviors>
  <serviceBehaviors>
    <behavior name="CalculatorServiceBehavior">
      <serviceMetadata httpGetEnabled="True"/>
      <serviceDebug includeExceptionDetailInFaults="False" />
    </behavior>
  </serviceBehaviors>
</behaviors>

Client Svcutil

Cet exemple n'utilise pas Svcutil.exe. Le contrat est fourni dans le fichier generatedClient.cs ; ainsi, après que l'exemple a illustré l'importation WSDL personnalisée et la génération de code, le service peut être appelé. Pour utiliser l'importateur WSDL personnalisé suivant pour cet exemple, vous pouvez exécuter Svcutil.exe et spécifier l'option /svcutilConfig, pour donner le chemin d'accès au fichier de configuration client utilisé dans cet exemple, qui fait référence à la bibliothèque WsdlDocumentation.dll. Pour charger l'WsdlDocumentationImporter, toutefois, Svuctil.exe doit être en mesure de localiser et charger la bibliothèque WsdlDocumentation.dll, ce qui signifie soit qu'elle est enregistrée dans le Global Assembly Cache, dans le chemin d'accès, soit qu'elle se trouve dans le même répertoire que Svcutil.exe. Pour un exemple de base tel que celui-ci, le plus simple est de copier Svcutil.exe et le fichier de configuration client dans le même répertoire que WsdlDocumentation.dll et l'exécuter à partir de là.

L'importateur WSDL personnalisé

L'objet IWsdlImportExtension personnalisé WsdlDocumentationImporter implémente également IContractBehavior et IOperationBehavior pour être ajouté aux ServiceEndpoints importés et IServiceContractGenerationExtension et IOperationContractGenerationExtension pour être appelé afin de modifier la génération du code lorsque le code du contrat ou de l'opération est créé.

En premier lieu, dans la méthode ImportContract, l'exemple détermine si l'annotation WSDL se trouve au niveau du contrat ou de l'opération, et s'ajoute lui-même en tant que comportement à l'étendue appropriée, en passant le texte d'annotation importé à son constructeur.

public void ImportContract(WsdlImporter importer, WsdlContractConversionContext context)
{
    // Contract Documentation
    if (context.WsdlPortType.Documentation != null)
    {
        // System examines the contract behaviors to see whether any implement IWsdlImportExtension.
        context.Contract.Behaviors.Add(new WsdlDocumentationImporter(context.WsdlPortType.Documentation));
    }
    // Operation Documentation
    foreach (Operation operation in context.WsdlPortType.Operations)
    {
        if (operation.Documentation != null)
        {
            OperationDescription operationDescription = context.Contract.Operations.Find(operation.Name);
            if (operationDescription != null)
            {
                // System examines the operation behaviors to see whether any implement IWsdlImportExtension.
                operationDescription.Behaviors.Add(new WsdlDocumentationImporter(operation.Documentation));
            }
        }
    }
}

Ensuite, lorsque le code est généré, le système appelle les méthodesGenerateContract et GenerateOperation, en passant les informations de contexte appropriées. L'exemple met en forme les annotations WSDL personnalisées et les insère comme commentaires dans le CodeDom.

public void GenerateContract(ServiceContractGenerationContext context)
{
    Debug.WriteLine("In generate contract.");
    context.ContractType.Comments.AddRange(FormatComments(text));
}

public void GenerateOperation(OperationContractGenerationContext context)
{
    context.SyncMethod.Comments.AddRange(FormatComments(text));
    Debug.WriteLine("In generate operation.");
}

L'application cliente

L'application cliente charge l'importateur WSDL personnalisé en le spécifiant dans le fichier de configuration de l'application.

<client>
  <endpoint address="https://localhost/servicemodelsamples/service.svc" 
  binding="wsHttpBinding" 
  contract="ICalculator" />
  <metadata>
    <wsdlImporters>
      <extension type="Microsoft.ServiceModel.Samples.WsdlDocumentationImporter, WsdlDocumentation"/>
    </wsdlImporters>
  </metadata>
</client>

Une fois que l'importateur personnalisé a été spécifié, le système de métadonnées WCF charge l'importateur personnalisé dans tout WsdlImporter créé à cette fin. Cet exemple utilise le MetadataExchangeClient pour télécharger les métadonnées, l'WsdlImporter correctement configuré pour importer les métadonnées à l'aide de l'importateur personnalisé que l'exemple crée, et le ServiceContractGenerator pour compiler les informations de contrat modifiées à la fois dans le code client Visual Basic et C# qui peut être utilisé dans Visual Studio pour prendre en charge Intellisense ou être compilé dans la documentation XML.

/// From WSDL Documentation:
/// 
/// <summary>The ICalculator contract performs basic calculation 
/// services.</summary> 
/// 
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://Microsoft.ServiceModel.Samples", ConfigurationName="ICalculator")]
public interface ICalculator
{
    
    /// From WSDL Documentation:
    /// 
    /// <summary>The Add operation adds two numbers and returns the 
    /// result.</summary><returns>The result of adding the two arguments 
    /// together.</returns><param name="n1">The first value to add.</param><param 
    /// name="n2">The second value to add.</param> 
    /// 
    [System.ServiceModel.OperationContractAttribute(Action="http://Microsoft.ServiceModel.Samples/ICalculator/Add", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/AddResponse")]
    double Add(double n1, double n2);
    
    /// From WSDL Documentation:
    /// 
    /// <summary>The Subtract operation subtracts the second argument from the 
    /// first.</summary><returns>The result of the second argument subtracted from the 
    /// first.</returns><param name="n1">The value from which the second is 
    /// subtracted.</param><param name="n2">The value that is subtracted from the 
    /// first.</param> 
    /// 
    [System.ServiceModel.OperationContractAttribute(Action="http://Microsoft.ServiceModel.Samples/ICalculator/Subtract", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/SubtractResponse")]
    double Subtract(double n1, double n2);
    
    /// From WSDL Documentation:
    /// 
    /// <summary>The Multiply operation multiplies two values.</summary><returns>The 
    /// result of multiplying the first and second arguments.</returns><param 
    /// name="n1">The first value to multiply.</param><param name="n2">The second value 
    /// to multiply.</param> 
    /// 
    [System.ServiceModel.OperationContractAttribute(Action="http://Microsoft.ServiceModel.Samples/ICalculator/Multiply", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/MultiplyResponse")]
    double Multiply(double n1, double n2);
    
    /// From WSDL Documentation:
    /// 
    /// <summary>The Divide operation returns the value of the first argument divided 
    /// by the second argument.</summary><returns>The result of dividing the first 
    /// argument by the second.</returns><param name="n1">The numerator.</param><param 
    /// name="n2">The denominator.</param> 
    /// 
    [System.ServiceModel.OperationContractAttribute(Action="http://Microsoft.ServiceModel.Samples/ICalculator/Divide", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/DivideResponse")]
    double Divide(double n1, double n2);
}

Pour configurer, générer et exécuter l'exemple

  1. Assurez-vous d'avoir effectué la procédure indiquée dans la section Procédure d'installation unique pour les exemples Windows Communication Foundation.

  2. Pour générer l'édition C# ou Visual Basic .NET de la solution, suivez les instructions indiquées dans Génération des exemples Windows Communication Foundation.

  3. Pour exécuter l'exemple dans une configuration à un ou plusieurs ordinateurs, suivez les instructions indiquées dans Exécution des exemples Windows Communication Foundation.

Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.