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