I have spent 5 hours on this, and I've already been up 30 hours writing this contract-first spec ("aggressive" deadline, ergo stupid) and I cannot see what I'm missing.
I do not want a one-way operation as I expect faults. I have already built a simple WCF service and examined the WSDL that it generates and it does round trip to a void method but I've been staring at it so long (and WSDL 1.1 is so annoying at the best of times - roll on 2.0 please) that I can no longer see what the magic trick is.
Can anyone provide some very simple WSDL explaining the magic? I'm targetting both jax-ws 2.2 and WCF 3.5/4.0 with this WSDL. I am hand-writing the WSDL and every time I try to build proxies (in java or .net) it always builds a method with the return message. I'm losing it.
A "void" method doesn't necessarily mean that it's a one-way operation. The two operations below are different:
[ServiceContract]
public interface ITest
{
[OperationContract(IsOneWay = true)]
void Process1();
[OperationContract]
void Process2();
}
The first one is really a one-way operation - any exceptions / faults thrown by the server will not be propagated to the client, while in the second one, although it doesn't "return" anything, if the server throws an exception (e.g., a FaultException
), the exception will be returned back to the caller.
Update: to answer the question posed in the title, the WSDL parser decides to generate a void operation (at least the one used by WCF) if the schema for the output message of the operation is empty.
For example, in the code below:
public class StackOverflow_8316567
{
[ServiceContract]
public interface ITest
{
[OperationContract(IsOneWay = true)]
void Process1();
[OperationContract]
void Process2();
[OperationContract]
int Add(int x, int y);
}
public class Service : ITest
{
public void Process1() { }
public void Process2() { }
public int Add(int x, int y) { return x + y; }
}
static Binding GetBinding()
{
var result = new BasicHttpBinding();
return result;
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(ITest), GetBinding(), "");
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
host.Open();
Console.WriteLine("Host opened");
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
If you run it and browse to http://localhost:8000/service?wsdl you'll see that:
Process1
(under wsdl:portType/wsdl:operation) only has an input messageAdd
and Process2
(r/r operations) have both an input and the output messagesNow, the message part for the output message for those 2 operations reference their schema in the imported schema (at http://localhost:8000/service?xsd=xsd0). You can see that:
Process2
operation (complex type Process2Response
) is an empty element (i.e., an empty sequence)Add
operation (AddResponse
) is a sequence containing one element (an xs:int
value).So the processor will generate a void
method for Process2
(since it doesn't return anything) and a non-void method for Add
.