Publication WSDL personnalisée
L’exemple WsdlDocumentation montre comment :
Implémenter une System.ServiceModel.Description.IWsdlExportExtension sur un attribut System.ServiceModel.Description.IContractBehavior personnalisé pour exporter les propriétés de l'attribut en tant qu'annotations WSDL ;
Implémenter System.ServiceModel.Description.IWsdlImportExtension pour importer les annotations WSDL personnalisées ;
Implémenter System.ServiceModel.Description.IServiceContractGenerationExtension et System.ServiceModel.Description.IOperationContractGenerationExtension sur un comportement de contrat personnalisé et un comportement d’opération personnalisé, respectivement, pour écrire des annotations importées en tant que commentaires dans le CodeDom pour le contrat et l’opération importés ;
Utilisez le System.ServiceModel.Description.MetadataExchangeClient pour télécharger le WSDL, un System.ServiceModel.Description.WsdlImporter pour importer le WSDL à l’aide de l’importateur WSDL personnalisé, et le System.ServiceModel.Description.ServiceContractGenerator pour générer le code client WCF (Windows Communication Foundation) avec les annotations WSDL en tant que commentaires /// et ’’’ en C# et Visual Basic.
Notes
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(WsdlExporter, WsdlContractConversionContext) 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: http://localhost/servicemodelsamples/service.svc -->
<endpoint address=""
binding="wsHttpBinding"
contract="Microsoft.ServiceModel.Samples.ICalculator" />
<!-- the mex endpoint is exposed at http://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(WsdlImporter, WsdlContractConversionContext), 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(ServiceContractGenerationContext) et GenerateOperation(OperationContractGenerationContext), 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="http://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
Assurez-vous d’avoir effectué la Procédure d’installation unique pour les exemples Windows Communication Foundation.
Pour générer l’édition C# ou Visual Basic .NET de la solution, conformez-vous aux instructions figurant dans Building the Windows Communication Foundation Samples.
Pour exécuter l’échantillon dans une configuration à un ou plusieurs ordinateurs, conformez-vous aux instructions fournies dans Exécution des échantillons Windows Communication Foundation.