Version one I found out was
ContractDescription cd = ContractDescription.GetContract(typeof(IContract));
System.ServiceModel.Description.WsdlExporter wexp = new System.ServiceModel.Description.WsdlExporter();
wexp.ExportContract(cd);
MetadataSet mds = wexp.GetGeneratedMetadata();
mds.WriteTo(new XmlTextWriter(@".\IContract.wsdl", Encoding.UTF8));
for a simple contract like
namespace WsdlExporter
{
[MessageContract]
public class RequestMessage
{
public Guid ID;
}
[MessageContract]
public class ResponseMessage
{
public string Name;
}
[ServiceContract(Namespace="http://www.mleder.blogspot.com/WsdlExporter/2008/04")]
public interface IContract
{
[OperationContract]
void Op1(string s);
[OperationContract]
int Op2();
[OperationContract]
ResponseMessage Op3(RequestMessage req);
}
}
I think this is verbose.
So I figured out version two, where I start with an "empty" WSDL file:
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:tns="http://localhost/remote"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
targetNamespace="http://localhost/remote"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://localhost/remote">
</s:schema>
</wsdl:types>
<wsdl:portType name="RemoteAddServiceSoap12">
</wsdl:portType>
<wsdl:binding name="RemoteAddServiceSoap12" type="tns:RemoteAddServiceSoap12">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
</wsdl:binding>
<wsdl:service name="RemoteAddService">
<wsdl:port name="RemoteAddServiceSoap12" binding="tns:RemoteAddServiceSoap12">
<soap12:address location="http://localhost:8765/RemoteAddService.asmx" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
and write some C# code:
// load an "empty" WSDL file (no types, messages, operations, ...)
// to start from and add operations by code
ServiceDescription wsdl = ServiceDescription.Read("empty.wsdl");
// add operation binding
OperationBinding myOperationBinding = new OperationBinding();
myOperationBinding.Name = "Add";
Soap12OperationBinding myOperation = new Soap12OperationBinding();
myOperation.Style = SoapBindingStyle.Document;
myOperation.SoapAction = "http://localhost/remote/Add";
myOperationBinding.Extensions.Add(myOperation);
// add input binding
InputBinding myInput = new InputBinding();
Soap12BodyBinding soap12BodyInputBinding = new Soap12BodyBinding();
soap12BodyInputBinding.Use = SoapBindingUse.Literal;
myInput.Extensions.Add(soap12BodyInputBinding);
myOperationBinding.Input = myInput;
// add output binding
OutputBinding myOutput = new OutputBinding();
Soap12BodyBinding soap12BodyOutputBinding = new Soap12BodyBinding();
soap12BodyOutputBinding.Use = SoapBindingUse.Literal;
myOutput.Extensions.Add(soap12BodyOutputBinding);
myOperationBinding.Output = myOutput;
wsdl.Bindings[0].Operations.Add(myOperationBinding);
// 1. ==> add operation to port type
Operation operation = new Operation();
operation.Name = "Add";
OperationMessage outputMessage = (OperationMessage)new OperationOutput();
outputMessage.Message = new XmlQualifiedName("tns:AddOutput");
OperationInput inputMessage = new OperationInput();
inputMessage.Message = new XmlQualifiedName("tns:AddInput");
operation.Messages.Add(inputMessage);
operation.Messages.Add(outputMessage);
wsdl.PortTypes[0].Operations.Add(operation);
// add first message
Message message1 = new Message();
message1.Name = "AddInput";
MessagePart messagePart1 = new MessagePart();
messagePart1.Name = "parameter1";
messagePart1.Type = new XmlQualifiedName("s:int");
MessagePart messagePart2 = new MessagePart();
messagePart2.Name = "parameter2";
messagePart2.Type = new XmlQualifiedName("s:int");
message1.Parts.Add(messagePart1);
message1.Parts.Add(messagePart2);
// add second message
Message message2 = new Message();
message2.Name = "AddOutput";
// add third message
MessagePart messagePart3 = new MessagePart();
messagePart3.Name = "result";
messagePart3.Type = new XmlQualifiedName("s:int");
message2.Parts.Add(messagePart3);
// 2. ==> add messages
wsdl.Messages.Add(message1);
wsdl.Messages.Add(message2);
// write the service description into a WSDL file.
wsdl.Write("empty_add.wsdl");
Console.WriteLine("WSDL file named empty_add.wsdl created successfully.");
Using version two, you have full control over all types, messages, operations, bindings, etc. and get a short and easy:
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:tns="http://localhost/remote" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" targetNamespace="http://localhost/remote" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://localhost/remote" />
</wsdl:types>
<wsdl:message name="AddInput">
<wsdl:part name="parameter1" type="s:int" />
<wsdl:part name="parameter2" type="s:int" />
</wsdl:message>
<wsdl:message name="AddOutput">
<wsdl:part name="result" type="s:int" />
</wsdl:message>
<wsdl:portType name="RemoteAddServiceSoap12">
<wsdl:operation name="Add">
<wsdl:input message="tns:AddInput" />
<wsdl:output message="tns:AddOutput" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="RemoteAddServiceSoap12" type="tns:RemoteAddServiceSoap12">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="Add">
<soap12:operation soapAction="http://localhost/remote/Add" style="document" />
<wsdl:input>
<soap12:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap12:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="RemoteAddService">
<wsdl:port name="RemoteAddServiceSoap12" binding="tns:RemoteAddServiceSoap12">
<soap12:address location="http://localhost:8765/RemoteAddService.asmx" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
To create a WCF proxy for C# :
svcutil -n:*,srRemoteAddService empty_add.wsdl
Hi Markus,
ReplyDeleteThank you for sharing this. It's very helpful.
I have a question for you if you can help. Instead of code, we only have XSD files as input. And we have to generate WSDL file programmatically based on those XSD files and fixed method in WCF service that looks as follows:
OutputMessage CustomAction(InputMessage) {...}
InputMessage should be body of SOAP message request and OutputMessage should be body of SOAP message response of WCF service that is running.
WSDL file should be generated on the fly as XML string and passed further to help running WCF service.
What do you think how can we do that?
Thank you in advance.
Goran
Hi Goran,
DeleteI want exactly the same (generate wsdl on the fly). (How) did you manage to do that?
Regards,
Dirk