Anpassad WSDL-publikation
WsdlDocumentation-exemplet visar hur du:
Implementera ett System.ServiceModel.Description.IWsdlExportExtension på ett anpassat System.ServiceModel.Description.IContractBehavior attribut för att exportera attributegenskaper som WSDL-anteckningar.
Implementera System.ServiceModel.Description.IWsdlImportExtension för att importera anpassade WSDL-anteckningar.
Implementera System.ServiceModel.Description.IServiceContractGenerationExtension och System.ServiceModel.Description.IOperationContractGenerationExtension på ett anpassat kontraktsbeteende respektive ett anpassat åtgärdsbeteende för att skriva importerade anteckningar som kommentarer i CodeDom för det importerade kontraktet och åtgärden.
System.ServiceModel.Description.MetadataExchangeClient Använd för att ladda ned WSDL, en System.ServiceModel.Description.WsdlImporter för att importera WSDL med hjälp av den anpassade WSDL-importören och System.ServiceModel.Description.ServiceContractGenerator för att generera WCF-klientkoden (Windows Communication Foundation) med WSDL-anteckningarna som /// och ''' kommentarer i C# och Visual Basic.
Kommentar
Installationsproceduren och bygginstruktionerna för det här exemplet finns i slutet av det här avsnittet.
Tjänst
Tjänsten i det här exemplet är markerad med två anpassade attribut. Den första, WsdlDocumentationAttribute
, accepterar en sträng i konstruktorn och kan användas för att tillhandahålla ett kontraktsgränssnitt eller en åtgärd med en sträng som beskriver dess användning. Den andra, WsdlParamOrReturnDocumentationAttribute
, kan användas för att returnera värden eller parametrar för att beskriva dessa värden i åtgärden. I följande exempel visas ett tjänstkontrakt, ICalculator
, som beskrivs med hjälp av dessa attribut.
// 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
);
}
Implementerar WsdlDocumentationAttribute
IContractBehavior och IOperationBehavior, så attributinstanserna läggs till i motsvarande ContractDescription eller OperationDescription när tjänsten öppnas. Attributet implementerar IWsdlExportExtensionockså . När ExportContract(WsdlExporter, WsdlContractConversionContext) anropas skickas det WsdlExporter som används för att exportera metadata och WsdlContractConversionContext som innehåller tjänstbeskrivningsobjekten som parametrar som möjliggör ändring av exporterade metadata.
I det här exemplet, beroende på om exportkontextobjektet har en ContractDescription eller en OperationDescription, extraheras en kommentar från attributet med hjälp av textegenskapen och läggs till i WSDL-anteckningselementet enligt följande kod.
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);
}
}
}
Om en åtgärd exporteras använder exemplet reflektion för att hämta värden WsdlParamOrReturnDocumentationAttribute
för parametrar och returvärden och lägger till dem i WSDL-anteckningselementen för åtgärden enligt följande.
// 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);
}
}
Exemplet publicerar sedan metadata på standardsättet med hjälp av följande konfigurationsfil.
<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>
Svcutil-klient
Det här exemplet använder inte Svcutil.exe. Kontraktet tillhandahålls i filen generatedClient.cs så att tjänsten kan anropas när exemplet visar anpassad WSDL-import och kodgenerering. Om du vill använda följande anpassade WSDL-importör för det här exemplet kan du köra Svcutil.exe och ange /svcutilConfig
alternativet, vilket ger sökvägen till klientkonfigurationsfilen som används i det här exemplet, som refererar till WsdlDocumentation.dll
biblioteket. För att läsa in WsdlDocumentationImporter
måste Svuctil.exe dock kunna hitta och läsa in WsdlDocumentation.dll
biblioteket, vilket innebär att det antingen är registrerat i den globala sammansättningscacheminnet, i sökvägen eller finns i samma katalog som Svcutil.exe. För ett grundläggande exempel som detta är det enklaste att göra att kopiera Svcutil.exe och klientkonfigurationsfilen till samma katalog som WsdlDocumentation.dll
och köra den därifrån.
Den anpassade WSDL-importören
Det anpassade IWsdlImportExtension objektet WsdlDocumentationImporter
implementerar IContractBehavior och IOperationBehavior läggs till i de importerade ServiceEndpoints och IServiceContractGenerationExtension anropas IOperationContractGenerationExtension för att ändra kodgenereringen när kontraktet eller åtgärdskoden skapas.
ImportContract(WsdlImporter, WsdlContractConversionContext) I metoden avgör exemplet först om WSDL-anteckningen är på kontrakt- eller åtgärdsnivå och lägger till sig själv som ett beteende i lämpligt omfång och skickar den importerade anteckningstexten till konstruktorn.
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));
}
}
}
}
När koden sedan genereras anropar GenerateContract(ServiceContractGenerationContext) systemet metoderna och GenerateOperation(OperationContractGenerationContext) skickar lämplig kontextinformation. Exemplet formaterar anpassade WSDL-anteckningar och infogar dem som kommentarer i 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.");
}
Klientprogrammet
Klientprogrammet läser in den anpassade WSDL-importören genom att ange den i programkonfigurationsfilen.
<client>
<endpoint address="http://localhost/servicemodelsamples/service.svc"
binding="wsHttpBinding"
contract="ICalculator" />
<metadata>
<wsdlImporters>
<extension type="Microsoft.ServiceModel.Samples.WsdlDocumentationImporter, WsdlDocumentation"/>
</wsdlImporters>
</metadata>
</client>
När den anpassade importören har angetts läser WCF-metadatasystemet in den anpassade importören till alla WsdlImporter som skapats för detta ändamål. Det här exemplet använder MetadataExchangeClient för att ladda ned metadata, den WsdlImporter korrekt konfigurerade för att importera metadata med hjälp av den anpassade importören som exemplet skapar, och för att kompilera den ändrade kontraktsinformationen ServiceContractGenerator till både Visual Basic- och C#-klientkoden som kan användas i Visual Studio för att stödja Intellisense eller kompileras till XML-dokumentation.
/// 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);
}
Så här konfigurerar du, skapar och kör exemplet
Kontrollera att du har utfört engångsinstallationsproceduren för Windows Communication Foundation-exempel.
Om du vill skapa C# eller Visual Basic .NET-versionen av lösningen följer du anvisningarna i Skapa Windows Communication Foundation-exempel.
Om du vill köra exemplet i en konfiguration med en eller flera datorer följer du anvisningarna i Köra Windows Communication Foundation-exempel.